gpt4 book ai didi

c++ - 在 copy-and-swap 习语中实现交换

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

正在关注 What is the copy and swap idiomHow to provide a swap function for my class ,我尝试像后者接受的答案选项 2 那样实现交换函数(具有调用成员函数的自由函数),而不是前一个链接中的直接友好自由函数。

但是下面的不编译

#include <iostream>

// Uncommenting the following two lines won't change the state of affairs
// class Bar;
// void swap(Bar &, Bar &);
class Bar {
public:
Bar(unsigned int bottles=0) : bottles(bottles) { enforce(); } // (1)
Bar(Bar const & b) : bottles(b.bottles) { enforce(); } // (1)

Bar & operator=(Bar const & b) {
// bottles = b.bottles;
// enforce();
// Copy and swap idiom (maybe overkill in this example)
Bar tmp(b); // but apart from resource management it allows (1)
// to enforce a constraint on the internal state
swap(*this, tmp); // Can't see the swap non-member function (2)
return *this;
}

void swap(Bar & that) {
using std::swap;
swap(bottles, that.bottles);
}

friend std::ostream & operator<<(std::ostream & out, Bar const & b) {
out << b.bottles << " bottles";
return out;
}

private:
unsigned int bottles;
void enforce() { bottles /=2; bottles *= 2; } // (1) -- Ensure the number of bottles is even
};

void swap(Bar & man, Bar & woman) { // (2)
man.swap(woman);
}

int main () {
Bar man (5);
Bar woman;

std::cout << "Before -> m: " << man << " / w: " << woman << std::endl;
swap(man, woman);
std::cout << "After -> m: " << man << " / w: " << woman << std::endl;

return 0;
}

我知道 copy-and-swap 习语在这里有点矫枉过正,但它也允许人们通过复制构造函数 (1) 对内部状态强制执行一些约束(一个更具体的例子是保持简化形式的分数)。不幸的是,这不会编译,因为编译器看到的 (2) 的唯一候选者是 Bar::swap 成员函数。我是否坚持使用好友非成员函数方法?

编辑:转至my answer below感谢对这个问题的所有回答和评论,看看我最终得到了什么。

最佳答案

我认为我们是后 C++11?

在这种情况下,std::swap 的默认实现将是最优的,前提是我们正确地实现了移动赋值运算符和移动构造函数(理想情况下不抛出)

http://en.cppreference.com/w/cpp/algorithm/swap

#include <iostream>

class Bar {
public:
Bar(unsigned int bottles=0) : bottles(bottles) { enforce(); } // (1)
Bar(Bar const & b) : bottles(b.bottles) {
// b has already been enforced. is enforce necessary here?
enforce();
} // (1)
Bar(Bar&& b) noexcept
: bottles(std::move(b.bottles))
{
// no need to enforce() because b will have already been enforced;
}

Bar& operator=(Bar&& b) noexcept
{
auto tmp = std::move(b);
swap(tmp);
return *this;
}

Bar & operator=(Bar const & b)
{
Bar tmp(b); // but apart from resource management it allows (1)
swap(tmp);
return *this;
}

void swap(Bar & that) noexcept {
using std::swap;
swap(bottles, that.bottles);
}

friend std::ostream & operator<<(std::ostream & out, Bar const & b) {
out << b.bottles << " bottles";
return out;
}

private:
unsigned int bottles;
void enforce() { } // (1)
};

/* not needed anymore
void swap(Bar & man, Bar & woman) { // (2)
man.swap(woman);
}
*/
int main () {
Bar man (5);
Bar woman;

std::cout << "Before -> m: " << man << " / w: " << woman << std::endl;
using std::swap;
swap(man, woman);
std::cout << "After -> m: " << man << " / w: " << woman << std::endl;

return 0;
}

预期结果:

Before -> m: 5 bottles / w: 0 bottles
After -> m: 0 bottles / w: 5 bottles

编辑:

为了关心性能的任何人(例如@JosephThompson)的利益,请允许我减轻您的顾虑。将对 std::swap 的调用移动到一个虚函数中(以强制 clang 生成任何代码),然后使用带有 -O2 的 apple clang 进行编译,这:

void doit(Bar& l, Bar& r) override {
std::swap(l, r);
}

变成了这个:

__ZN8swapper24doitER3BarS1_:            ## @_ZN8swapper24doitER3BarS1_
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp85:
.cfi_def_cfa_offset 16
Ltmp86:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp87:
.cfi_def_cfa_register %rbp
movl (%rsi), %eax
movl (%rdx), %ecx
movl %ecx, (%rsi)
movl %eax, (%rdx)
popq %rbp
retq
.cfi_endproc

看到了吗?最佳的。 C++ 标准库棒极了!

关于c++ - 在 copy-and-swap 习语中实现交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36010810/

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