Переместить конструктор в список инициализаторов с вектором

С этим образцом:

// 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

Но, если я инициализирую v значением r:

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

Я не понимаю две вещи:

  • Почему для строк без необработанных данных выполняется второе перемещение (до первого копирования / перемещения)?
  • Почему с необработанными строками копии mystring не выполняются?

0

Решение

Нотабене необработанные строки означают что-то другое в C ++ 11, я думаю, что вы имеете в виду строковый литерал, если вы говорите о "hello"

  • Почему с необработанными строками копии mystring не выполняются?

А? Там есть одна копия, поэтому она печатает Const Reference,

vector<mystring> v{"hello"};

Braced-init-list инициализирует std::initializer_list<mystring> параметр конструктора с одним элементом, который строится с использованием mystring(const char* c) конструктор, то этот элемент копируется в вектор с помощью mystring(const mystring&) конструктор, который печатает Const Reference, Довольно просто

  • Почему для строк без необработанных данных выполняется второе перемещение (до первого копирования / перемещения)?

Как может быть второй ход перед первым ходом ?! 🙂

Это деталь реализации того, как initializer_list построен, что обычно не имеет значения, потому что дополнительные ходы будут исключены.

vector <mystring> v{mystring()};

Это создает временный mystring используя конструктор по умолчанию, затем создает std::initializer_list<mystring> с одним элементом, который построен с использованием mystring(mystring&&) конструктор с временным в качестве аргумента. Что двигать строительные принты Move, Есть еще один шаг внутри, печать Move снова. Тогда initializer_list элемент копируется в вектор как и раньше, печатается Const Reference,

Чтобы ответить на ваш комментарий:

Дополнительное перемещение, которое вы видите, также происходит в первом случае, но в этом случае перемещаемый тип 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);

когда expr является a (который является неконстантным lvalue) создание tmp печать Reference затем создание tmparray печать Moveзатем копирование tmparray[0] в векторной печати Const Reference,

когда expr является "hello" создавая элементы tmp ничего не печатает, а создает tmparray звонки mystring(const char*) который ничего не печатает, затем копирует tmparray[0] в векторной печати Const Reference,

когда expr является mystring() создание tmp печать Move затем создание tmparray печать Move затем копирование tmparray[0] в векторной печати 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() } ты получаешь Move напечатано один раз tmp2 а также Move напечатано один раз tmparray а также Const Reference напечатаны дважды элементами v,

Конечно, обычно все это удаляется, поэтому нет ненужных копий или ходов. -fno-elide-constructors не очень полезно, кроме как выяснить, что произойдет, но на самом деле не происходит!

2

Другие решения

Вы неправильно пометили конструктор перемещения как noexcept,

0

По вопросам рекламы [email protected]