我看到许多代码在 copy-and-swap 方面实现了5的规则,但是我认为我们可以使用移动函数来替换交换函数,如以下代码所示:
#include <algorithm>
#include <cstddef>
class DumbArray {
public:
DumbArray(std::size_t size = 0)
: size_(size), array_(size_ ? new int[size_]() : nullptr) {
}
DumbArray(const DumbArray& that)
: size_(that.size_), array_(size_ ? new int[size_] : nullptr) {
std::copy(that.array_, that.array_ + size_, array_);
}
DumbArray(DumbArray&& that) : DumbArray() {
move_to_this(that);
}
~DumbArray() {
delete [] array_;
}
DumbArray& operator=(DumbArray that) {
move_to_this(that);
return *this;
}
private:
void move_to_this(DumbArray &that) {
delete [] array_;
array_ = that.array_;
size_ = that.size_;
that.array_ = nullptr;
that.size_ = 0;
}
private:
std::size_t size_;
int* array_;
};
我认为这段代码
我对吗?
谢谢
编辑:
move_to_this()
和析构函数DumbArray& operator=(DumbArray that) { move_to_this(that); return *this; }
分为DumbArray& operator=(const DumbArray &that) { DumbArray temp(that); move_to_this(temp); return *this; }
(感谢@MikeMB)和DumbArray& operator=(DumbArray &&that) { move_to_this(that); return *this; }
,以避免额外的移动操作添加一些调试打印后,我发现当您将它作为移动分配
DumbArray& operator=(DumbArray that) {}
中没有涉及任何额外的移动delete
move_to_this()
之前需要进行自我分配检查 最佳答案
内联评论,但简短地:
noexcept
。如果启用此功能,则标准库会更快,因为标准库可以消除对对象序列重新排序的算法中的任何异常处理。 代码:
#include <algorithm>
#include <cstddef>
class DumbArray {
public:
DumbArray(std::size_t size = 0)
: size_(size), array_(size_ ? new int[size_]() : nullptr) {
}
DumbArray(const DumbArray& that)
: size_(that.size_), array_(size_ ? new int[size_] : nullptr) {
std::copy(that.array_, that.array_ + size_, array_);
}
// the move constructor becomes the heart of all move operations.
// note that it is noexcept - this means our object will behave well
// when contained by a std:: container
DumbArray(DumbArray&& that) noexcept
: size_(that.size_)
, array_(that.array_)
{
that.size_ = 0;
that.array_ = nullptr;
}
// noexcept, otherwise all kinds of nasty things can happen
~DumbArray() // noexcept - this is implied.
{
delete [] array_;
}
// I see that you were doing by re-using the assignment operator
// for copy-assignment and move-assignment but unfortunately
// that was preventing us from making the move-assignment operator
// noexcept (see later)
DumbArray& operator=(const DumbArray& that)
{
// copy-swap idiom provides strong exception guarantee for no cost
DumbArray(that).swap(*this);
return *this;
}
// move-assignment is now noexcept (because move-constructor is noexcept
// and swap is noexcept) This makes vector manipulations of DumbArray
// many orders of magnitude faster than they would otherwise be
// (e.g. insert, partition, sort, etc)
DumbArray& operator=(DumbArray&& that) noexcept {
DumbArray(std::move(that)).swap(*this);
return *this;
}
// provide a noexcept swap. It's the heart of all move and copy ops
// and again, providing it helps std containers and algorithms
// to be efficient. Standard idioms exist because they work.
void swap(DumbArray& that) noexcept {
std::swap(size_, that.size_);
std::swap(array_, that.array_);
}
private:
std::size_t size_;
int* array_;
};
可以在移动分配运算符中进行进一步的性能改进。
我提供的解决方案保证了从中移出的数组将为空(资源已释放)。这可能不是您想要的。例如,如果您分别跟踪DumbArray的容量和大小(例如,类似于std::vector),那么您很可能希望在移动之后将
this
中分配的所有内存保留在that
中。然后这将允许that
分配给它,而可能无需其他内存分配就可以离开。为了实现这种优化,我们只需按照(noexcept)交换来实现move-assign运算符:
所以从这个:
/// @pre that must be in a valid state
/// @post that is guaranteed to be empty() and not allocated()
///
DumbArray& operator=(DumbArray&& that) noexcept {
DumbArray(std::move(that)).swap(*this);
return *this;
}
对此:
/// @pre that must be in a valid state
/// @post that will be in an undefined but valid state
DumbArray& operator=(DumbArray&& that) noexcept {
swap(that);
return *this;
}
就DumbArray而言,在实践中使用更宽松的形式可能值得,但要提防细微的错误。
例如
DumbArray x = { .... };
do_something(std::move(x));
// here: we will get a segfault if we implement the fully destructive
// variant. The optimised variant *may* not crash, it may just do
// something_else with some previously-used data.
// depending on your application, this may be a security risk
something_else(x);
关于c++ - 在C++ 11中实现 copy-and-swap 习惯的更好方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37915088/