【问题标题】:In copy-initialization, is the call to the copy constructor explicit or implicit?在复制初始化中,对复制构造函数的调用是显式的还是隐式的?
【发布时间】:2014-02-17 06:43:43
【问题描述】:
class AAA {
public:
    explicit AAA(const AAA&) {}
    AAA(int) {}
};


int main() {
    AAA a = 1;
    return 0;
}

据我了解,在上面的代码中,尽管在大多数情况下都省略了,但在语义上仍然需要调用复制构造函数。我的问题是,调用是显式的还是隐式的?很长一段时间以来,我一直认为对 AAA::AAA(int) 的调用是隐式的,但对复制构造函数的调用却不是。今天不小心弄到g++编译上面的代码,报错了。 (VC12编译OK。)

在标准的第 8.5 节中:

如果目标类型是(可能是 cv 限定的)类类型:

  • 如果初始化是直接初始化,或者如果是复制初始化,其中源的 cv 不合格版本 type 与该类的类相同或派生类 目的地,构造函数被考虑。适用的构造函数 枚举(13.3.1.3),通过重载选择最好的 决议(13.3)。调用如此选择的构造函数进行初始化 对象,以初始化表达式或表达式列表作为其 论点。如果没有构造函数适用,或者重载决议是 模棱两可,初始化格式不正确。

  • 否则(即,对于剩余的复制初始化情况),可以从源转换的用户定义的转换序列 类型为目标类型或(使用转换函数时) 其派生类的枚举如 13.3.1.4 中所述, 最好的一个是通过重载决议(13.3)选择的。如果 转换无法完成或不明确,初始化是 格式不正确。使用初始化程序调用所选函数 表达式作为其参数;如果函数是构造函数,则调用 初始化 cv 不合格版本的临时版本 目的地类型。临时是prvalue。调用结果 (这是构造函数的临时情况)然后用于 direct-initialize,根据上面的规则,对象就是 复制初始化的目的地。在某些情况下,一个 允许实施以消除在此固有的复制 通过直接构造中间结果来直接初始化 进入正在初始化的对象;见 12.2、12.8。

上面引号中的粗体direct-initialize 表示对复制构造函数的调用是显式的,对吗?是 g++ 错了还是我对标准的解释错了?

【问题讨论】:

    标签: c++ g++ language-lawyer


    【解决方案1】:

    看起来像这个错误:g++ fails to call explicit constructors in the second step of copy initialization

    g++编译以下代码失败

    struct X
    {
        X(int) {}
        explicit X(X const &) {}
    };
    
    int main()
    {
        X x = 1; // error: no matching function for call to 'X::X(X)'
    }
    

    副本初始化的第二步(参见 8.5/16/6/2)是 应考虑显式构造函数的直接初始化 作为候选函数。

    【讨论】:

    • 非常感谢。这解释了。
    • 这不是错误:en.cppreference.com/w/cpp/language/explicit“指定不允许隐式转换或复制初始化的构造函数和(C++11 起)转换运算符。”标记构造函数显式禁用复制-初始化。你必须做 X x(1);
    【解决方案2】:

    看起来复制构造函数从未被调用过。只有构造函数被调用。以下代码可能会调用复制构造函数

    AAA a = 1;
    AAA ab = a;
    

    不知道为什么 G++ 会编译它。

    【讨论】:

      猜你喜欢
      • 2018-08-03
      • 2012-08-16
      • 1970-01-01
      • 2020-10-29
      • 2015-10-24
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      相关资源
      最近更新 更多