代码之家  ›  专栏  ›  技术社区  ›  icecrime

显式复制构造函数行为和实际用途

c++
  •  38
  • icecrime  · 技术社区  · 14 年前

    最近的一个问题让我想知道显式复制构造函数。下面是我在Visual Studio 2005下尝试编译的示例代码:

    struct A
    {
        A() {}
        explicit A(const A &) {}
    };
    
    // #1 > Compilation error (expected behavior)
    A retByValue()
    {
        return A();
    }
    
    // #2 > Compiles just fine, but why ?
    void passByValue(A a)
    {
    }
    
    int main()
    {
        A a;
        A b(a); // #3 > explicit copy construction : OK (expected behavior)
        A c = a; // #4 > implicit copy construction : KO (expected behavior)
    
        // Added after multiple comments : not an error according to VS 2005.
        passByValue(a);
        return 0;
    }
    

    现在回答以下问题:

    • 标准允许2吗?如果是,描述这种情况的相关章节是什么?
    • 你知道显式复制构造函数有什么实际用途吗?

    [编辑] MSDN 与完全相同的情况下,还有一个神秘的评论来自于主要功能:“c是复制的”(好像很明显)。正如Oli Charlesworth所指出的:gcc不编译这段代码,我相信他不编译是对的。

    4 回复  |  直到 7 年前
        1
  •  41
  •   outis    14 年前

    我相信C++ 03的相关部分是 §12.3.1 二:

    显式构造函数像非显式构造函数一样构造对象,但仅在直接初始化语法( 8.5 5.2.9 , 5.4 )是明确使用的。默认构造函数可以是显式构造函数;此类构造函数将用于执行默认初始化或值初始化( 8.5条 ).

    § 8.5 12点:

    在参数传递、函数返回、引发异常时发生的初始化( 15.1 ),处理异常( 15.3 ),并用大括号括起初始值设定项列表( 8.5.1

        T x = a;
    

    在新表达式中发生的初始化( 5.3.4 ),静态转换表达式( 5.2.9条 ),函数表示法类型转换( 5.2.3 ),以及基和成员初始值设定项( 12.6.2 )称为直接初始化,相当于

        T x(a);
    

    打电话 passByValue(a)

        2
  •  5
  •   MSalters    14 年前

    定义 passByValue retByValue 当然还有一个复制对象的返回语句。

        3
  •  3
  •   CashCow    9 年前

    在C++ 11之前,使用复制构造函数显式的一个实际用途是,它实际上是使类不可复制的一部分。

    危险在于,尽管您声明了复制构造函数private并且没有实现它,但是如果您在friend中或在类本身中意外地复制了一个构造函数,编译器将不会接收它,您只会得到一个很难找到的链接错误。

    同样地,使它显式也减少了这样做的可能性,因为编译器很可能会获取您无意中的副本并指向您正在执行的实际行。

    在C++ 11(和14)中,在使用时不需要这样做。 =delete 语法,因为即使在类本身或朋友内部进行复制,也会出现编译器错误。

        4
  •  2
  •   Oliver Charlesworth    14 年前

    如果要添加 passByValue(a); 给你的 main() 函数,编译器 应该抱怨。

    显式复制构造函数是为了防止这种情况的发生,即防止函数调用中资源的隐式复制等(本质上它强制用户通过引用传递而不是通过值传递)。