简体   繁体   English

私有复制构造函数/赋值运算符和复制初始化

[英]private copy constructor/assignment operator and copy-initialization

This is a followup of this question这是这个问题的后续

in the following code, why does line 1 compiles while line 2 and 3 does not (using visual C++ 2010)在下面的代码中,为什么第 1 行编译而第 2 行和第 3 行没有编译(使用视觉 C++ 2010)

class ABase
{
protected:
    ABase() {}
    ~ABase() {}
private:
    ABase( const ABase& );
    const ABase& operator=( const ABase& );
};

class A : ABase
{
};

class B
{
public:
    B() {}
    ~B() {}
private:
    B( const B& );
    const B& operator=( const B& );
};

int main( void )
{
    A a = A(); // line 1
    A a2( a ); // line 2
    B b = B(); // line 3

    return 0;
}

(note BA is a copy of boost::noncopyable) (注意 BA 是 boost::noncopyable 的副本)

edit: My problem is not to know why line 2 and 3 does not compile (I know that, the copy constructor is private), but why line 1 does.编辑:我的问题是不知道为什么第 2 行和第 3 行不编译(我知道,复制构造函数是私有的),但为什么第 1 行编译。

Indeed line 1 should not compile.确实第 1 行不应该编译。

Apparently vc++2010 has problems enforcing language rules in this case (may be because they're related to a base class and not to the object itself).显然 vc++2010 在这种情况下执行语言规则存在问题(可能是因为它们与基础 class 相关,而不是与 object 本身相关)。

g++ diagnostic message about line 1 is very clear g++ 关于第 1 行的诊断信息非常清楚

ncopy.cpp: In copy constructor ‘A::A(const A&)’:
ncopy.cpp:7: error: ‘ABase::ABase(const ABase&)’ is private
ncopy.cpp:12: error: within this context
ncopy.cpp: In function ‘int main()’:
ncopy.cpp:27: note: synthesized method ‘A::A(const A&)’ first required here 

The compiler is wrong in accepting the first use.编译器在接受第一次使用时是错误的。 Even if the copy is elided, the copy constructor must be accessible for the code to be correct.即使省略了副本,也必须可以访问复制构造函数以使代码正确。

In this particular case there is an implicitly declared copy constructor in A :在这种特殊情况下, A中有一个隐式声明的复制构造函数:

§12.8/4 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. §12.8/4 如果 class 定义未显式声明复制构造函数,则隐式声明。

That is implicitly defined:这是隐式定义的:

§12.8/7 An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type108). §12.8/7 An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type108). [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2). [注意:复制构造函数是隐式定义的,即使实现省略了它的使用(12.2)。 ] A program is ill-formed if the class for which a copy constructor is implicitly defined has: ] 如果隐式定义了复制构造函数的class具有:

— a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or — class 类型(或其数组)的非静态数据成员,具有不可访问或不明确的复制构造函数,或

— a base class with an inaccessible or ambiguous copy constructor. 具有不可访问或不明确的复制构造函数的基本 class

ABase( const ABase& );

The copy constructor is made private so a copy of the class object cannot be created using this private copy constructor resulting in error.复制构造函数是私有的,因此无法使用此私有复制构造函数创建 class object 的副本,从而导致错误。

A a = A(); // line 1

Uses the A::A(const A&) to create a new A object.使用A::A(const A&)创建一个新A object。 A is derived from ABase and it calls ABase::ABase(const ABase&) in its constructor, which is private to it wont compile either. A是从ABase派生的,它在其构造函数中调用ABase::ABase(const ABase&) ,它是私有的,也不会编译。

Here is the output on Ideone.这是Ideone上的 output。 It doesn't compile even on gcc.它甚至在 gcc 上也无法编译。

Why it works on Visual studio?为什么它适用于 Visual Studio?
The reason is a possible Return Value optimization by the visual C++ compiler which elides the copy constructor.原因是可视 C++ 编译器可能对返回值进行优化,该编译器省略了复制构造函数。

As per the C++ standard, 12.8 copying class objects section 15根据 C++ 标准, 12.8 复制 class 对象第 15 节

When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.当满足某些条件时,允许实现省略 class object 的复制构造,即使 object 的复制构造函数和/或析构函数具有副作用。 In such cases, the implemen-tation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.111)在这种情况下,实现将省略的复制操作的源和目标简单地视为引用同一 object 的两种不同方式,并且该 object 的破坏发生在两个对象将被没有优化就被破坏了.111)

See my answer here which cites the Standard and the example code in this regard.请参阅我的答案here ,其中引用了这方面的标准和示例代码。

A a2( a ); // line 2

Does not compile for the same reason that ABase::ABase(const ABase&) is private.不编译的原因与ABase::ABase(const ABase&)是私有的相同。

 B b = B(); // line 3

Does not compile because B( const B& );不编译,因为B( const B& ); is private.是私人的。

Line 1 is a return value optimization (the compiler sees that there is no need to create a temporary variable for A() and use the copy constructor/assignment operator to assign to variable a ).第 1 行是返回值优化(编译器看到不需要为A()创建临时变量并使用复制构造函数/赋值运算符来分配给变量a )。 However, this does not compile on GCC (version 4.2.1) and should be avoided.但是,这不会在 GCC(版本 4.2.1)上编译,应该避免。

Line 2 does not compile because the compiler isn't generating an assignment operator for you in this case.第 2 行无法编译,因为在这种情况下编译器不会为您生成赋值运算符。 Line 3 is not compiling, as you expect.如您所料,第 3 行没有编译。

Reagan summary: line 1 works because it's Microsoft, the others behave as expected.里根总结:第 1 行有效,因为它是微软,其他的表现如预期。

Why does line 1 compile?为什么第 1 行编译? Because your compiler is broken;因为你的编译器坏了; it shouldn't, according to the standard.根据标准,它不应该。 While your class A has an implicitly declared copy constructor, §12.8/7 of the standard states that An implicitly-declared copy constructor will be implicitly defined if it is used to initialize an object (as in A a = A(); ), and that a program is ill formed (and thus requiring a diagnostic) if the constructor is implicitly defiend and a base class has an inaccessible or ambiguous copy constructor.虽然您的 class A具有隐式声明的复制构造函数,但标准的第 12.8/7 节规定,如果隐式声明的复制构造函数用于初始化 object(如A a = A(); ),则将隐式定义隐式声明的复制构造函数,并且如果构造函数被隐式定义并且基础 class 具有不可访问或不明确的复制构造函数,则程序格式错误(因此需要诊断)。 There's even a note saying this is the case even if the implementation elides the copy constructor.甚至有一个注释说即使实现省略了复制构造函数也是如此。 You're compiler is not going far enough: it sees the implicitly declared public copy constructor, but it doesn't try to implicitly define it, even though the standard clearly says it should.你的编译器还不够:它看到隐式声明的公共复制构造函数,但它不会尝试隐式定义它,即使标准明确表示应该这样做。

I believe it is because the constructor is protected, not private.我相信这是因为构造函数是受保护的,而不是私有的。 The compiler provided constructor in class A is free to call the protected constructor of class ABase, so it works.编译器在 class A 中提供的构造函数可以自由调用 class ABase 的受保护构造函数,因此可以正常工作。

Also, line 1 is not a copy constructor.此外,第 1 行不是复制构造函数。 A declaration with an assignment is a special case which is converted into a constructor.带有赋值的声明是一种特殊情况,它被转换为构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM