gpt4 book ai didi

c++ - 我什么时候需要交换功能?

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

当我编写持有资源的类时,我非常习惯于编写简单的交换函数来简化传输/复制资源的过程。以下代码是一个简单的示例:

class MyArray {
public:
MyArray(size_t size) :
_array(size ? new int[size] : nullptr),
_size(size)
{
}

MyArray(const MyArray & mv) :
MyArray(mv._size)
{
if(mv._size) std::copy(mv._array, mv._array + mv._size, _array);
}

static void friend swap(MyArray & mv1, MyArray & mv2) noexcept {
std::swap(mv1._array, mv2._array);
std::swap(mv1._size, mv2._size);
}

MyArray(MyArray && mv) {
swap(*this, mv);
}

MyArray & operator=(MyArray mv) {
swap(*this, mv);
return *this;
}

~MyArray() noexcept {
delete[] _array;
}

int & operator[](size_t index) {
if(index >= _size) throw std::exception("Index Out of Bounds!");
return _array[index];
}

const int & operator[](size_t index) const {
if(index >= _size) throw std::exception("Index Out of Bounds!");
return _array[index];
}

size_t size() const {
return _size;
}
private:
int * _array;
size_t _size;
};

但是,我可以选择[等效地] 实现相同的代码,如下所示:

class MyArray {
public:
MyArray(size_t size) :
_array(size)
{
}

int & operator[](size_t size) {
if(index >= size()) throw std::exception("Index Out of Bounds!");
return _array[index];
}

const int & operator[](size_t index) const {
if(index >= size()) throw std::exception("Index Out of Bounds!");
return _array[index];
}

size_t size() const {
return _array.size();
}

private:
std::vector<int> _array;
};

在第二个代码中,swap 功能默认为正常的 std::swap 行为(即移动构造第一个到临时,移动分配到第二个进入第一个,并将临时分配给第二个),这应该与第一个代码相同(在设计层面)。

然后我的问题是,我必须显式定义 swap 函数的场景是什么,但不是我只是尝试重用代码的具体场景 (就像第一个示例代码)?是否存在明显(或不太明显)的场景,即使我的代码中没有任何内容明确管理资源,我也会客观地受益于 swap 函数?我应该为我编写的每个 [move-constructable] 类自动编写一个 swap 函数,还是这样做只会浪费代码?

最佳答案

如果你没有定义自己的交换操作,using std::swap; swap(lhs, rhs); 大致编译为:

auto tmp = std::move(rhs);
rhs = std::move(lhs);
lhs = std::move(tmp);

这会导致发生 3 次移动,并且需要存在一个完整的临时对象。

如果移动分配和移动构造运算符具有强异常保证,则此交换具有弱异常保证。如果移动赋值和移动构造运算符没有被抛出,那么这个交换也是。

相比之下,成员交换可能会使对象处于不连贯的状态。如果您的代码可以处理此问题,则意味着您永远不必创建完整的临时对象。因此,如果您可以处理部分交换的组件,并且完整的临时对象(通过移动创建)有一些成本,那么成员交换可能会更快。

但是,如果所有内容都不是抛出(交换/移动通常是),则产生的交换操作在逻辑上是等价的。


您的第二个 MyArray 实际上并不管理资源。这是由 std::vector 处理的,它确实编写了您第一个代码中的大部分代码。

零规则是不管理资源的类不需要编写任何复制或移动赋值或构造,也不需要编写析构函数。这样的类可能也不需要交换。

执行复制/移动和销毁的类,管理资源的类,可以使用交换来实现。否则,std::swap 做得不错。


顺便说一句,如果他们确实使用交换,并且交换只是按成员进行的,请这样写:

friend auto mytie( MyArray& self ) noexcept {
return std::tie(self.array, self.size);
}

然后交换变成:

friend void swap( MyArray& lhs, MyArray& rhs ) noexcept {
std::swap( mytie(lhs), mytie(rhs) );
}

这会将您的“重复成员姓名”样板计数减少 1。

关于c++ - 我什么时候需要交换功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37930494/

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