【问题标题】:Effects of using "=" in object construction在对象构造中使用“=”的效果
【发布时间】:2016-11-20 01:32:21
【问题描述】:

另一个 C++ 问题,我试图弄清楚在构造对象时使用“=”有什么影响。考虑:

class Foo {
    private:
        int bar;
        int baz;

    public:
        Foo(int bar, int baz)
            :bar(bar), baz(baz) {}
};

int main() {
    Foo foo1{4, 2};
    Foo foo2 = {4, 2};
    Foo foo3 = Foo{4, 2}; // I prefer this one for aesthetic reasons.

    return 0;
}

有什么区别?我应该坚持哪一个作为最佳做法?

此外,当我们讨论最佳实践的主题时,我听说将 explicit 添加到构造函数是一个好主意™,因为隐式转换的奇怪行为。所以我在Foo的构造函数中添加了explicit

    public:
        explicit Foo(int bar, int baz)
            :bar(bar), baz(baz) {}

突然,这个:

    Foo foo2 = {4, 2};

编译失败,报错:

error: chosen constructor is explicit in copy-initialization

这是为什么呢?

【问题讨论】:

  • 重要的两个区别: 1) 如您所见,复制初始化不适用于显式构造函数。 2) auto 在复制和直接初始化之间推导 std::initializer_list 的方式不同。其余的,它在 C++17 中变得没有意义。
  • Foo foo3 = Foo{4, 2}; // I prefer this one. 我不知道为什么。从概念上讲,它涉及一个完全没有意义的额外副本,尽管实际上一个好的优化编译器会消除你的错误。但它只是看起来冗长而丑陋。当它是多余的时候,为什么要写得比你必须写的多? Foo foo{4, 2}; 更胜一筹。
  • “我听说向构造函数添加显式...” - 除了是一个可怕的笼统陈述之外,您听到的任何地方的未提及作者是否提到 为什么 他们认为这是一个好主意?你同意,不同意,还是根本不理解这个理由?最后,this description of explicit 值得回顾。
  • 另请注意,auto 将始终推断出 std::initializer_list 的上述规则被视为缺陷并在 C++17 中修复 - 其中 auto thing = {a, b} 具有 2+ 个元素仍将推断出std::initializer_list 但是 例如auto str{ std::to_string(num) }; 现在将正确地 IMO 推断要构造的类型。这样做的非常正确的理由是它避免了我们必须记住两组规则 - 从而使统一初始化,嗯,统一。值得注意的是 g++ 已经将其向后移植到旧标准,但 Clang 没有(可以说更有礼貌!)
  • @underscore_d “我不知道为什么”,美学。我不知道这就是为什么我要问的陈述之间的区别。

标签: c++ c++11 constructor initialization initializer-list


【解决方案1】:

有什么区别

Foo foo1{4, 2};

这是direct initialization (2)

直接初始化在以下情况下进行:

2) 在列表初始化序列期间,如果没有提供初始化器列表构造函数并且可以访问匹配的构造函数,并且所有必要的隐式转换都是非窄化的。


Foo foo2 = {4, 2};

这是copy list initialization (6)。非直接列表初始化不考虑显式构造函数。这就解释了为什么在显式更改构造函数时程序没有编译。

复制列表初始化(只能调用非显式构造函数)

6) 在等号后使用花括号初始化列表初始化命名变量


Foo foo3 = Foo{4, 2};

这是一个临时对象的direct list initialization (2),然后是临时对象的copy initialization (1)

直接列表初始化(显式和非显式构造函数都考虑在内)

2) 使用花括号初始化列表初始化未命名的临时对象


复制初始化在以下情况下进行:

2) 当一个非引用类型 T 的命名变量(自动、静态或线程局部)被声明时,其初始化程序由等号后跟一个表达式组成。


首先是最简单的,这就是我喜欢它的原因。

第二个需要一个隐式构造函数,但其​​他都可以。

第三个涉及类型的重复(违反DRY),并构造了一个不必要的临时(实际上,优化器可能会省略副本,但类型必须是可复制的)。

我听说向构造函数添加显式是一个好主意™。所以我在 Foo 的构造函数中添加了显式

如果要防止隐式转换,向单参数构造函数添加显式是一个好主意。显式对于两个参数构造函数并不是那么普遍有用,但我不怀疑在某些情况下你会需要它。

【讨论】:

    猜你喜欢
    • 2019-09-12
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多