gpt4 book ai didi

c++ - 使用 move-constructor 时将 self 重置为 nullptr 是个好习惯吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:17:41 25 4
gpt4 key购买 nike

在 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_;
};

看起来不错,但有时我想移动一个局部变量,像这样:

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_时,a_的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_);
}
};

在这段代码中,当我移动一些东西时,我会交换新旧引用,所以旧的 tmp 将删除[]原来的 a_ table_,这是无用的。

这样做是个好习惯。

最佳答案

当您从 A(A && other) 中的 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 置于标准调用的有效但未指定状态

你也可以使用 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;
}

当移动对象被销毁时,这种方式将完成释放。

关于c++ - 使用 move-constructor 时将 self 重置为 nullptr 是个好习惯吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43387487/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com