gpt4 book ai didi

c++ - 使用 vector 在初始化列表中 move 构造函数

转载 作者:行者123 更新时间:2023-11-28 03:26:14 31 4
gpt4 key购买 nike

使用这个示例:

// test.cpp

#include <iostream>
#include <vector>
#include <utility>

using namespace std;

class mystring : public string { public:
mystring() = default;

mystring(const char* c) : string(c) {}

mystring(mystring& m) : string(m) { cout << "Reference" << endl; }
mystring(mystring const & m) : string(m) { cout << "Const reference" << endl; }
mystring(mystring&& m) : string(move(m)) { cout << "Move" << endl; }
};

int main() {
mystring a;

vector<mystring> v{ a };
}

输出是:

$ g++ --version | grep "g++"
g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
$ g++ -std=c++11 -fno-elide-constructors test.cpp
$ ./a.out
Reference
Move
Const reference

但是,如果我用 r 值初始化 v:

vector<mystring> v{"hello"};

输出是:

$ g++ -std=c++11 -fno-elide-constructors test.cpp
$ ./a.out
Const reference

也就是说,没有拷贝。使用 r 值:

vector <mystring> v{mystring()};

输出:

$ g++ -std=c++11 -fno-elide-constructors test.cpp
$ ./a.out
Move
Move
Const reference

我不明白两件事:

  • 为什么使用非原始字符串执行第二步(在第一次复制/move 之前)?
  • 为什么对于原始字符串,不执行“mystring”的拷贝?

最佳答案

注意原始字符串在 C++11 中意味着不同的东西,如果你在谈论 "hello",我认为你的意思是字符串文字

  • Why with raw strings, no copies of "mystring" are performed?

嗯?只有一份,这就是它打印 Const Reference 的原因.

vector<mystring> v{"hello"};

braced-init-list 初始化 std::initializer_list<mystring>具有单个元素的构造函数参数,使用 mystring(const char* c) 构造构造函数,然后使用 mystring(const mystring&) 将该元素复制到 vector 中构造函数,打印 Const Reference .很简单。

  • Why with no-raw strings a second move (before the first copy/move) is performed?

第二步怎么可能先于第一步?! :)

它是 initializer_list 的实现细节构造,这通常无关紧要,因为额外的 move 将被省略。

vector <mystring> v{mystring()};

这会创建一个临时的 mystring使用默认构造函数,然后创建 std::initializer_list<mystring>使用单个元素,它是使用 mystring(mystring&&) 构造的以临时作为参数的构造函数。搬家施工打印Move .内部还有另一个 Action ,打印 Move再次。然后 initializer_list元素像以前一样复制到 vector 中,打印Const Reference .

回答您的评论:

您看到的额外 move 也发生在第一种情况下,但在这种情况下, move 的类型是 const char*所以它不打印 Move即声明 std::vector<mystring>{ expr };可以认为是:

auto tmp = expr;
mystring tmparray[] = { std::move(tmp) };
std::initializer_list<mystring> init_list( tmparray, 1 };
std::vector<mystring> v(init_list);

expra (这是一个非常量左值)创建 tmp版画 Reference然后创建 tmparray版画 Move然后复制 tmparray[0]进入 vector 打印 Const Reference .

expr"hello"创建 tmp 的元素不打印任何东西,并创建 tmparray电话 mystring(const char*)它不打印任何东西,然后复制 tmparray[0]进入 vector 打印 Const Reference .

exprmystring()创建tmp版画 Move然后创建 tmparray版画 Move然后复制 tmparray[0]进入 vector 打印 Const Reference

有一个像{ expr1, expr2 } 这样的两个元素的花括号初始化列表它可以被认为是:

auto tmp1 = expr1;
auto tmp2 = expr2;
mystring tmparray[] = { std::move(tmp1), std::move(tmp2) };
std::initializer_list<mystring> init_list( tmparray, 2 };
std::vector<mystring> v(init_list);

所以如果你使用 { "hello", mystring() }你得到 Movetmp2 打印一次和 Movetmparray 打印一次和 Const Referencev 的元素打印两次.

当然,通常所有这些都会被删除,因此没有不必要的复制或 move 。 -fno-elide-constructors除了找出会发生什么,实际上并没有用,但实际上并没有发生!

关于c++ - 使用 vector 在初始化列表中 move 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13878818/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com