在C ++ 11中,move-constructor / operator支持资源/内存移动。
这是我的例子:
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_;
};
看起来不错,但有时候我想移动一个局部变量,如下所示:
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.
}
};
当函数结束时,tmp.~A()
将被调用,此时a_
和tmp
具有相同的table_
指针,tmp delete[] table_
时{ {1}}无效。
我在何时应该使用a_'s table_
将tmp分配给a_,而不是复制。
在答案的帮助下,我修改了A的移动构造函数,如下所示:
std::move
在这段代码中,当我移动某些东西时,我会交换旧的和旧的引用,因此旧的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_);
}
};
将删除[]原始的a_ table_,这是无用的。
这是一个很好的习惯。
答案 0 :(得分:4)
当您从other
中的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;
}
这会将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;
}
这样,当从对象移动时,将完成释放。
答案 1 :(得分:2)
这段代码有很多问题(即使你想要摆弄数组和指针,你现在也不应该这样做。只需使用std :: vector)。
错误代码:
<li *ngIf="Games?.length == 0">
<span class="search_no_results">
No data found
</span>
</li>
请勿在ctor正文中使用赋值,请使用member-init-lists。好代码:
A()
{
table_ = nullptr;
alloc_ = 0;
}
同样适用于其他构造者。
冗余代码:
A() : table{nullptr}, alloc_ {0} {}
if (table_)
delete[] table_;
将再次检查您的指针。 delete
delete
非常安全。不要打扰。
非常错误代码:
nullptr
A(const A & other)
{
if (table_)
delete[] table_;
未初始化。访问它是UB。而且,没有必要在构造函数中进行此检查。新构造的对象中不会有任何分配。只需删除支票即可。与其他建设者一样。
错误代码:
table
不防止自我指派。同样适用于其他任务操作员。
无论您是编写C ++ 03还是C ++ 11代码,都需要学习这些习惯。现在移动:
A& operator=(const A & other)
{
if (table_)
delete[] table_;
这是完全错误的。您需要更改从移动的对象,否则它根本不是移动,只是简单的浅层复制。
A(A && other)
{
if (table_)
delete[] table_;
table_ = other.table_;
alloc_ = other.alloc_;
}
同样适合移动工作。
移动中的 A(A && other) : table_{other.table_}, alloc_{other.alloc_} {
{
other.table_ = nullptr;
other.alloc_ = 0;
}
当你处理用户定义的类型时,ctor是一个很好的习惯用法。原始类型并不完全需要,主要是因为你需要先将它们初始化然后立即交换,但你可以使用它。
答案 2 :(得分:1)
您的移动构造函数和赋值运算符正在有效地执行浅拷贝。您应该将other.table
设置为nullptr
,以便在这种情况下有意义。当然,这将避免两次删除相同数组时的未定义行为,如您在示例中所建议的那样。
答案 3 :(得分:1)
一个很好的选择是交换移动构造函数中的值。
A& operator=(A && other)
{
using namespace std;
swap(table_, other.table_);
swap(alloc_, other.alloc_);
return *this;
}
这样,源的内容被放置在目标中,后者的内容被转移到源 - 然后在被删除时将正确地清理它们(这是你期望的,否则,你不会想要移动对象......)。
移动构造函数可以从上面的赋值中获利:
A(A&& other) : A()
{
*this = std::move(other);
}
答案 4 :(得分:1)
在移动构造函数/赋值中,复制指针后,将它们指定为“nullptr”,这样当析构函数被调用时,它将不是操作。
这是我如何去编写移动构造函数和赋值。而且,你可以避免“如果”检查“删除”,如果它是“nullptr”,它将不是操作。
A(A && other)
{
delete[] table_;
table_ = other.table_;
other.table_ = nullptr;
alloc_ = other.alloc_;
}
A& operator=(A && other) {
delete[] table_;
table_ = other.table_;
other.table_ = nullptr; // assign the source to be nullptr
alloc_ = other.alloc_;
return *this;
}
答案 5 :(得分:0)
我认为您需要更改移动构造函数和赋值运算符,如下所示:
// Simple move constructor
A(A&& arg) : member(std::move(arg.member)) // the expression "arg.member" is lvalue
{}
// Simple move assignment operator
A& operator=(A&& other) {
member = std::move(other.member);
return *this;
}
定义为here