У меня три вопроса:
Память A :: str выделена в области видимости функции f. Перемещает ли его элемент в глобальный var vec, остается ли блок памяти безопасным, если он выходит за рамки f?
Для структуры B, не дающей явно конструктор перемещения, есть ли такой по умолчанию, как структура A?
struct A
{
A(const char* p):str(p){}
A(const A&& a) : str(std::move(a.str))
{
}
string str;
};
struct B
{
B(const char* p):str(p){}
string str;
};
vector<A>vec;
void f()
{
vec.emplace_back(A("hello")); //in vc2010 it will invoke emplace_back(T&&)
}
int _tmain(int argc, _TCHAR* argv[])
{
f();
const char* p = vec[0].str.c_str();
cout << p << endl;
return 0;
}
3. И могу ли я подтвердить, что эта опасная ситуация никогда не возникает в контейнере STL?
struct String
{
char* pStr; //allocate on heap
int* someptr; //if point to allocate on stack
size_t len;
String (const String&& s)
{
// something like this:
pStr = s.pStr; //ok,safe
len = s.len;
s.pStr = nullptr;
someptr = s.someptr; //danger
}
};
Это безопасно, потому что память, выделенная для временного объекта A, «перемещается» в элемент вектора.
В VC ++ 2010 конструктор перемещения автоматически не создавался, но VC ++ 2010 был выпущен до того, как был закончен стандарт C ++ 11, и правила для конструкторов перемещения / операторов присваивания несколько изменились. Я не уверен, что VC ++ 2012 генерирует их, но в любом случае это безопасно (единственное отличие — его можно скопировать или переместить).
Любая память, выделенная внутри A::str
контролируется им и никак не зависит от того, какая сфера действия действовала, когда A
был создан. Так что ваш код совершенно безопасен.
Когда вы не определяете ни конструктор копирования, ни конструктор перемещения (ни оператор назначения копирования / перемещения), компилятор сгенерирует их для вас. Так B
имеет сгенерированный по умолчанию конструктор перемещения, идентичный A
один.