首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Coding
V2EX  ›  C

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

  •  1
     
  •   alanlian · 89 天前 · 1921 次点击
    这是一个创建于 89 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想问一下 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);
        }
    };
    
    27 回复  |  直到 2019-09-13 17:41:00 +08:00
        1
    ysc3839   89 天前 via Android
    因为 mSize 和 mArray 是 private 的,所以需要声明成 friend 才能访问。
        2
    alanlian   89 天前
    @ysc3839 应该不是这个原因吧?我去掉 friend 还是可以编译成功
        3
    Tony042   89 天前
    同意楼上的,另外 friend 声明写在 public 上面吧,还有 declaration 和 definition 最好分开写,写在一起很乱
        4
    alanlian   89 天前
    @Tony042 emm 这个只是一个小 sample,是我给的链接里的回答者拿来说明 copy-and-swap idiom 这个问题的,他好像是特意把 friend 写在那个位置的?可以看一下我给的链接
        5
    ysc3839   89 天前 via Android
    @alanlian 发代码看看?
        6
    psuwgipgf   89 天前
    @Tony042 friend 写在哪里都行,因为他不是类的成员,不过一般是写在开头或结尾
        7
    alanlian   89 天前
    @ysc3839 可以看下我给的链接,在 A successful solution 这一节,我是直接 copy 里面的代码的
        8
    secondwtq   89 天前
    friend 好像是只能写在这吧 ...
    这里 swap 是个成员函数,成员函数是可以不加 friend 访问自己的 private 成员的

    之前好像没见过这么写 copy-and-swap idiom 的(不过 C++11 之后好像不用这个 idiom 也可以了
        9
    secondwtq   89 天前
    啊等等我好像搞混了,无视掉 #8 的评论吧 ... 我再看看
        10
    cyyzero   89 天前 via Android   ♥ 1
    没有 friend 就是成员函数了啊
        11
    tianshilei1992   89 天前
    那段代码应该这样写才是直观的:
    class dumb_array {
    public:
    friend void swap(dumb_array& first, dumb_array& second);
    };

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

    你不写 friend 的话就变成类中的函数了,要使用的话会变成 a.swap(a, b) 这种样子。
        17
    namehao   89 天前   ♥ 2
    不加 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()的定制版。这样就是直接将类内的指针进行交换,而不用进行额外的拷贝构造函数的调用。

    不知这样,讲明白了没有。
        18
    alanlian   89 天前
    @namehao 谢谢您,明白了
        19
    alanlian   89 天前
    @ysc3839 也谢谢您
        20
    namehao   89 天前 via iPhone
    @alanlian 不客气
        21
    secondwtq   89 天前 via iPad
    这个不是重载的 std::swap,这个新函数应该是通过 ADL 被找到的
        22
    alanlian   88 天前
    @secondwtq https://stackoverflow.com/questions/11562/how-to-overload-stdswap 这个链接里的这个巨巨也是用的 overload 这个词呢?您看下
        23
    secondwtq   88 天前   ♥ 1
    @alanlian 意思类似于:
    Q:传输大文件用什么服务最吼?
    A:顺丰快递
    你感受一下

    标准对 overload 的定义:“When two or more different declarations are specified for a single name **in the same scope**, that name is said to be overloaded.”
    technically,你在使用 swap 的时候用了 overload resolution 的机制,overload resolution 在决定 candidate set 的时候会考虑 scope 和 ADL。不过 overload resolution 和 overloading 是两回事
        24
    alanlian   88 天前
    @secondwtq 这样子,我大概明白了,谢谢您了
        25
    secondwtq   88 天前
    其实应该说,你正确调用 swap 的时候,把 std::swap 重载了
    另外 C++20 之前调 std::swap 应该是不会调到你的 swap 去的
        26
    baixiangcpp   88 天前
    《 EFFective C++》肯定没好好看
        27
    baixiangcpp   88 天前
    接上条,没写完就发了) 里边专门有个条款,就讲了 swap,虽然《 C++ primer 》也提过一嘴,但是一笔带过了.....
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4176 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 28ms · UTC 08:04 · PVG 16:04 · LAX 00:04 · JFK 03:04
    ♥ Do have faith in what you're doing.