关于 cpp 的 copy-and-swap idiom 的问题

2019-09-12 22:57:37 +08:00
 alanlian

想问一下 https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom/3279550#3279550 这个链接里的这个下面这段 public: friend 是怎么理解的呢? po 主尽力看了原回答给的链接,有些没有看懂。

class dumb_array
{
public:
    friend void swap(dumb_array& first, dumb_array& second) // nothrow
    {
        // enable ADL (not necessary in our case, but good practice)
        using std::swap;

        // by swapping the members of two objects,
        // the two objects are effectively swapped
        swap(first.mSize, second.mSize);
        swap(first.mArray, second.mArray);
    }
};
4455 次点击
所在节点    C++
27 条回复
ysc3839
2019-09-12 23:27:26 +08:00
因为 mSize 和 mArray 是 private 的,所以需要声明成 friend 才能访问。
alanlian
2019-09-13 00:01:12 +08:00
@ysc3839 应该不是这个原因吧?我去掉 friend 还是可以编译成功
Tony042
2019-09-13 00:01:29 +08:00
同意楼上的,另外 friend 声明写在 public 上面吧,还有 declaration 和 definition 最好分开写,写在一起很乱
alanlian
2019-09-13 00:05:15 +08:00
@Tony042 emm 这个只是一个小 sample,是我给的链接里的回答者拿来说明 copy-and-swap idiom 这个问题的,他好像是特意把 friend 写在那个位置的?可以看一下我给的链接
ysc3839
2019-09-13 00:05:25 +08:00
@alanlian 发代码看看?
psuwgipgf
2019-09-13 00:05:26 +08:00
@Tony042 friend 写在哪里都行,因为他不是类的成员,不过一般是写在开头或结尾
alanlian
2019-09-13 00:08:22 +08:00
@ysc3839 可以看下我给的链接,在 A successful solution 这一节,我是直接 copy 里面的代码的
secondwtq
2019-09-13 01:15:56 +08:00
friend 好像是只能写在这吧 ...
这里 swap 是个成员函数,成员函数是可以不加 friend 访问自己的 private 成员的

之前好像没见过这么写 copy-and-swap idiom 的(不过 C++11 之后好像不用这个 idiom 也可以了
secondwtq
2019-09-13 01:24:00 +08:00
啊等等我好像搞混了,无视掉 #8 的评论吧 ... 我再看看
cyyzero
2019-09-13 01:57:39 +08:00
没有 friend 就是成员函数了啊
tianshilei1992
2019-09-13 07:40:25 +08:00
那段代码应该这样写才是直观的:
class dumb_array {
public:
friend void swap(dumb_array& first, dumb_array& second);
};

void swap(dumb_array& first, dumb_array& second) {
...
}
类里面的那个函数是“声明”,下面的那一段才是真正的“定义”。因为在函数的实现里面用到了类的私有成员,因此就必须得将这个函数在类里面声明成 friend 才可以。
ysc3839
2019-09-13 08:44:47 +08:00
@alanlian 我要的是你的“我去掉 friend 还是可以编译成功”的代码。链接中的代码是有 firend 的。
alanlian
2019-09-13 10:50:03 +08:00
@ysc3839 https://paste.ubuntu.com/p/C9bNY8XBJV/ 大约是这样的,你看有什么问题麽?
alanlian
2019-09-13 10:59:22 +08:00
@cyyzero 惭愧了,直接做一个成员函数会有什么问题么?
alanlian
2019-09-13 10:59:53 +08:00
@tianshilei1992 但是为什么不可以直接作为一个成员函数呢?
ysc3839
2019-09-13 11:01:34 +08:00
@alanlian 因为没有在类外部调用 swap,所以没问题吧。
代码中给出的用法是 std::swap 这样单独一个函数的 https://en.cppreference.com/w/cpp/algorithm/swap

你不写 friend 的话就变成类中的函数了,要使用的话会变成 a.swap(a, b) 这种样子。
namehao
2019-09-13 11:39:53 +08:00
不加 friend 是可以编译成功的,这样的 swap 是类的一个成员函数,对于 operator=这样的操作也是没有问题的。

但是对于如果在类的外部调写这样的代码。比如在 main 函数中写:dumb_array a, b; std::swap(a, b);那么在 c++11 中是 c=move(a),a = move(b), b = move(c)这样的操作,因为 dumb_array 没有写移动构造和移动赋值函数,就导致会调用拷贝构造函数。

这样导致的问题就是,swap 本来可以直接将类内的数组指针值进行替换,却多构造了一个临时数组,来进行换值操作。

当把 swap()写成 friend 之后,swap 就成了 std::swap()的一个重载函数,当在 main 中进行 std::swap(a,b)调用的时候,调用到的就是作为 friend 函数的 swap,也就是 std::swap()的定制版。这样就是直接将类内的指针进行交换,而不用进行额外的拷贝构造函数的调用。

不知这样,讲明白了没有。
alanlian
2019-09-13 12:14:20 +08:00
@namehao 谢谢您,明白了
alanlian
2019-09-13 12:14:58 +08:00
@ysc3839 也谢谢您
namehao
2019-09-13 13:14:38 +08:00
@alanlian 不客气

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/600536

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX