我想在我的应用程序中使用移动语义,而不是复制数据。
using namespace std;
struct TestData
{
TestData(const TestData&) = delete;
TestData& operator=(const TestData&) = delete;
TestData(TestData &&other) = default;
TestData& operator=(TestData &&other) = default;
TestData() { std::cout << "TestData()" << std::endl; }
~TestData() noexcept {
if(ptr != null) delete []ptr;
std::cout << "~TestData(), ptr = " << (ptr == nullptr ? "nullptr" : "not null") << std::endl;
}
int x;
char *ptr = nullptr;
};
void add(std::vector<TestData> &vector)
{
TestData d;
d.x = 1;
d.ptr = new char[12];
memcpy(d.ptr, "Test string", 11);
vector.push_back(d);
}
int main()
{
std::vector<TestData> v;
add(v);
add(v);
return 0;
}
但是GCC编译器出错了:
错误:使用被删除的函数'TestData::TestData(const TestData&)'。
但是我不想复制数据,我想移动数据。原因是复制数据会导致复制指针(ptr),所以试图在destructor中删除它会导致双自由损坏。
所以问题是--如何强制GCC使用移动构造函数?
这个调用
vector.push_back(d);
不调用你的移动构造函数,因为 d
不是一个r值引用。如果对非 r-value 引用调用 move 构造函数,那就不好了,因为它会把本应保持完整的对象的内脏撕掉。你需要投射到 r-value 引用,以明确你不再需要 d
. 这就是 std::move
(它实际上只是一个投射)。
vector.push_back(std::move(d));
然而,默认的move构造函数 TestData
是做的不对。在上面一行字之后 ptr
仍然是被移出的对象所拥有,从而导致双重删除。您可以通过使用 std::string
作为成员,而非 char *
.