【发布时间】:2020-11-11 11:03:52
【问题描述】:
我在理解与移动语义和对象一起使用的向量的概念时遇到了问题。我把代码放上来,把问题准确地解释给你,因为我很想了解这背后的逻辑。
#include <iostream>
#include <vector>
#include <cstring>
#include "Mystring.h"
using namespace std;
class Mystring {
private:
char* str;
public:
Mystring();
Mystring(const char* s);
Mystring(const Mystring& source);
Mystring(Mystring&& source);
~Mystring();
Mystring& operator=(const Mystring& rhs);
Mystring& operator=(Mystring&& rhs);
void display() const;
int get_lenght() const;
const char* get_str() const;
};
int main() {
vector <Mystring> stooges_vec;
stooges_vec.push_back("Larry"); //11
stooges_vec.push_back("Moe"); //12
stooges_vec.push_back("Curly"); //13
return 0;
}
//One-args constructor
Mystring::Mystring(const char* s)
: str{ nullptr } {
if (s == nullptr) {
str = new char[1];
*str = '\0';
}
else {
str = new char[std::strlen(s) + 1];
std::strcpy(str, s);
}
}
//Copy constructor
Mystring::Mystring(const Mystring& source)
:str{ nullptr } {
str = new char[std::strlen(source.str) + 1];
std::strcpy(str, source.str);
}
//Move constructor
Mystring::Mystring(Mystring&& source)
:str{ source.str } {
source.str = nullptr;
std::cout << "Move constructor called." << std::endl;
}
//Destructor
Mystring::~Mystring() {
delete[] str;
}
//Copy assignment
Mystring& Mystring::operator=(const Mystring& rhs) {
std::cout << "Copy assignment called." << std::endl;
if (this == &rhs)
return *this;
delete[] str;
str = new char[std::strlen(rhs.str) + 1];
std::strcpy(str, rhs.str);
return *this;
}
//Move assignment
Mystring& Mystring::operator=(Mystring&& rhs) {
std::cout << "Move assignment called." << std::endl;
if (this == &rhs)
return *this;
delete[] str;
str = rhs.str;
rhs.str = nullptr;
return *this;
}
所以,问题是我不明白这个程序的过程。我拿了调试器,一切都很好:
-
对于我要添加的第一个对象,首先调用“一个 args 构造函数”,因此我创建了我的对象,然后调用了“移动构造函数”,因此我窃取了数据并将原始对象的指针设为空。我完成它,将我的对象推入向量中,然后销毁现在包含空指针的原始对象。
-
在这里我永远迷路了,因为过程看起来一样,除了在
std::cout << "Move constructor called." << std::endl;行之后,控件转到复制构造函数,我注意到(我希望我没有错)他复制了@987654324 @。
问题是:我不知道编译器为什么要复制Larry。它就在那里,所以编译器不能简单地创建Moe,使用移动语义并将Moe 推到向量的后面吗?为什么一定要复制?
另外,对我来说,一个非常奇怪的行为是我看到在 Larry 的复制构造函数之后调用了一个析构函数,因为我看到它被破坏了。我的意思是,此时编译器正在破坏什么?原来的Larry 所以它保留了副本,或者那里到底发生了什么?
有人可以向我解释那一秒 push_back() 到底发生了什么吗?
【问题讨论】:
-
试试这个,但使用 emplace_back 而不是 push_back
-
我也用过emplace_back,情况也是一样。关键是我不理解在第二个 push_back 上调用的复制构造函数,它也是 emplace_back 的相同行为。
-
离题,但你的赋值运算符不是异常安全的。你先
delete[]new[]。