在 C++11 中,移动构造函数/运算符支持资源/内存移动。
这是我的例子:
class A {
public:
A() : table_(nullptr), alloc_(0) {}
~A()
{
if (table_)
delete[] table_;
}
A(const A & other)
{
// table_ is not initialized
// if (table_)
// delete[] table_;
table_ = new int[other.alloc_];
memcpy(table_, other.table_, other.alloc_ * sizeof(int));
alloc_ = other.alloc_;
}
A& operator=(const A & other)
{
if (table_)
delete[] table_;
table_ = new int[other.alloc_];
memcpy(table_, other.table_, other.alloc_ * sizeof(int));
alloc_ = other.alloc_;
return *this;
}
A(A && other)
{
// table_ is not initialized in constructor
// if (table_)
// delete[] table_;
table_ = other.table_;
alloc_ = other.alloc_;
}
A& operator=(A && other)
{
if (table_)
delete[] table_;
table_ = other.table_;
alloc_ = other.alloc_;
}
private:
int *table_;
int alloc_;
};
Run Code Online (Sandbox Code Playgroud)
看起来不错,但有时我想移动一个局部变量,如下所示:
class B {
private:
A a_;
public:
void hello()
{
A tmp;
// do something to tmp
a_ = std::move(tmp);
// tmp.~A() is called, so a_ is invalid now.
}
};
Run Code Online (Sandbox Code Playgroud)
当函数结束时,tmp.~A()将被调用,此时,a_和tmp具有相同的table_指针,当tmp delete[] table_,a_'s table_将无效。
我在徘徊什么时候应该使用std::move将 tmp 分配给 a_,而无需复制。
在答案的帮助下,我像这样修改了 A 的移动构造函数:
class A {
private:
void reset()
{
table_ = nullptr;
alloc_ = 0;
}
public:
A(A && other)
{
table_ = other.table_;
alloc_ = other.alloc_;
other.reset();
}
A& operator=(A && other)
{
std::swap(table_, other.table_);
std::swap(alloc_, other.alloc_);
}
};
Run Code Online (Sandbox Code Playgroud)
在这段代码中,当我移动一些东西时,我会交换新旧引用,因此旧的tmp将删除[]原始a_ table_,这是无用的。
这是一个很好的习惯。
当您从otherin移动时A(A && other),您还应该将其移动的数据成员设置为 nulltpr。所以固定代码应该如下所示:
A(A && other)
{
//if (table_)
// delete[] table_; // no need for this in move c-tor
table_ = other.table_;
other.table_ = nullptr;
alloc_ = other.alloc_;
other.alloc_ = nullptr;
}
A& operator=(A && other)
{
// as n.m. has pointed out, this move assignment does not
// protect against self assignment. One solution is to use
// swap aproach here. The other is to simply check if table_ == other.table_.
// Also see here for drawbacks of swap method:
// http://scottmeyers.blogspot.com/2014/06/the-drawbacks-of-implementing-move.html
delete[] table_;
table_ = other.table_;
other.table_ = nullptr;
alloc_ = other.alloc_;
other.alloc_ = nullptr;
return *this;
}
Run Code Online (Sandbox Code Playgroud)
这放入other了标准调用的内容valid but unspecified state。
你也可以使用 std::swap 如下:
A(A && other)
{
table_ = other.table_;
alloc_ = other.alloc_;
}
A& operator=(A && other)
{
std::swap(table_, other.table_);
std::swap(alloc_, other.alloc_);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
当从对象被销毁时,这种方式将完成释放。
| 归档时间: |
|
| 查看次数: |
784 次 |
| 最近记录: |