【问题标题】:When should you use direct initialization and when copy initialization?什么时候应该使用直接初始化,什么时候应该使用复制初始化?
【发布时间】:2011-05-16 16:02:27
【问题描述】:

这仅仅是偏好还是有特定的情况需要一个而不是另一个?我指的是以下变体进行初始化

T t(e); // direct initialization
T t = e; // copy initialization

【问题讨论】:

  • 什么是隐式赋值?你的意思是默认赋值运算符吗?
  • “隐式赋值”是什么意思。
  • @Mike:都不是赋值,它们都是初始化。
  • @Mike:这些都不是作业。你只是编造了这个词。它们是复制初始化,因此它们是相同的。
  • 我已将您的帖子修正为更接近您想要询问的内容。

标签: c++ implicit-conversion explicit-constructor copy-initialization


【解决方案1】:

您描述的事物的实际名称不是隐式和显式赋值,而是:

  • 复制初始化:T x = a;
  • 直接初始化:T x(a);

它们等价,尤其是在需要转换的上下文中,例如,当T 属于类类型而a 属于不同类型时(参见 Alf 注释的示例甚至不涉及转换的上下文)。考虑以下代码:

class Test
{
public:
    explicit Test(int i) { /* ... */ }
};

int main()
{
    Test t(0);  // OK : calls Test::Test(int)
    Test u = 0; // KO : constructor is marked explicit
}

解释标准(8.5/14):

  • 对于源类型与目标类相同或派生类的直接初始化和复制初始化,考虑构造函数
  • 对于其他复制初始化情况,例如我的示例中main 的第二行,考虑了用户定义的转换顺序。由于 explicit 关键字不允许使用 Test 构造函数进行隐式转换,因此第二行编译失败。

【讨论】:

  • “它们在需要转换的上下文中是不等价的”——在其他情况下它们也不等价。
  • @Alf:我不确定我是什么时候写这句话的,但是我找不到任何例子。我在这里的术语可能是错误的,因为我在您的答案中看到的 is 转换(通过标准称为 converting constructor),实际上非常类似于我的答案(除了我没有涉及的花括号部分)。我错过了什么?
  • 好吧,假设a 是表达式T()。 :-) 然后复制初始化语法形式大多等同于默认初始化(除了它可能涉及临时和复制),而直接初始化语法形式产生解释为函数声明,“最令人烦恼的解析”。另外,考虑explicit 复制构造函数的情况。并根据在这里的模糊程度考虑,考虑花括号初始化程序。所以,至少有3个案例。但直接的反例是explicitcopy 构造函数。干杯,
  • @Alf:我明白了 :) 我绝对不会想到这些!
【解决方案2】:

直接初始化喜欢

std::istringstream  stream( "blah blah" );

当相关类型(此处为 C++ 标准库中的 std::istringstream)没有可访问的复制构造函数时,这是必需的。

一个复制初始化,比如

std::istringstream  stream = "blah blah";   //! NOT VALID

需要一个可访问的复制构造函数,因为它的执行就像在= 的右侧创建了一个临时对象,并且好像该临时对象随后用于初始化正在声明的变量。

另一方面,在 C++98 中,需要复制初始化语法才能使用 花括号初始化器。例如,直接初始化不能用于初始化聚合。但是你可以使用带有花括号初始化器的复制初始化:

#include <string>
using namespace std;

struct Answer
{
    int     nVotes;
    string  description;
};    

int main()
{
    Answer const  incorrect   = { 26, "they're the same!" };
    Answer const  correct     = { -1, "nah, they're different, actually" };
}

因此,存在显着差异。

由于清晰,我通常更喜欢复制初始化语法。但有时,如上所示,不幸的是,直接初始化是必要的。有些人,例如C++ 教科书作者 Francis Glassborow 转而将直接初始化作为他们首选的初始化语法(我不知道为什么,我的眼睛不太清楚,并引入了“最令人头疼的解析”问题),对他们来说,这是必要的在某些情况下复制初始化,这是不幸的。

干杯,

【讨论】:

  • 这个答案写于 2010 年。使用 C++11 复制初始化 syntax 可以在更多情况下使用,因为它简化为 C++11 移动语义。此外,直接初始化语法已扩展为包含大括号值列表。
猜你喜欢
  • 2013-08-17
  • 1970-01-01
  • 2017-05-10
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多