【发布时间】:2012-11-21 13:05:50
【问题描述】:
12.6.1 - 显式初始化
struct complex {
complex();
complex(double);
complex(double,double);
};
complex sqrt(complex,complex);
complex g = { 1, 2 }; // construct complex(1, 2)
// using complex(double, double)
// and *copy/move* it into g
8.5 初始化器
14 - 表单中发生的初始化
T x = a;以及参数传递、函数返回、抛出异常 (15.1)、处理异常 (15.3)、聚合成员 初始化 (8.5.1) 称为复制初始化。 [笔记: 复制初始化可能会调用移动(12.8)。 ——尾注]
15 - 表单中发生的初始化
T x(a);
T x{a};以及在新表达式 (5.3.4) 中的 static_cast 表达式 (5.2.9),功能符号类型转换(5.2.3),以及基础和 成员初始化器 (12.6.2) 称为直接初始化。
8.5.4 列表初始化 [dcl.init.list]
1 - 列表初始化是对象或引用的初始化 一个花括号初始化列表。这样的初始化器称为初始化器列表, 列表中以逗号分隔的初始化子句称为 初始化列表的元素。初始化列表可能为空。 列表初始化可以发生在直接初始化或复制初始化中 上下文;列表初始化 直接初始化上下文称为直接列表初始化和 复制初始化上下文中的列表初始化被称为 复制列表初始化。
原子问题
29.6.5 原子类型操作的要求 [atomics.types.operations.req]
#define ATOMIC_VAR_INIT(value)见下文宏扩展为适合常量的记号序列 a 的静态存储持续时间的原子变量的初始化 与值初始化兼容的类型。 [注:这 操作可能需要初始化锁。 — 尾注] 并发访问 到被初始化的变量,即使是通过原子操作, 构成数据竞赛。 [ 例子:
atomic<int> v = ATOMIC_VAR_INIT(5);
根据前面的部分,似乎不应该在没有涉及复制构造函数的情况下进行赋值初始化,即使它根据 §12.8.31 和 §12.8.32 被省略,但原子定义为:
29.5 原子类型 [atomics.types.generic]
atomic() noexcept = default;
constexpr atomic(T) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
T operator=(T) volatile noexcept;
T operator=(T) noexcept;
没有复制构造函数!
ATOMIC_VAR_INIT 通常会扩展为大括号表达式以进行大括号初始化,但 atomic<int> v = {5} 仍然是赋值初始化,并且会暗示在直接构造临时变量之后进行复制构造。
我查看了“常量初始化”部分,看看是否存在允许在没有副本的情况下执行此操作的漏洞(因为“宏扩展为一个令牌序列,适合于对静态存储持续时间的原子变量进行常量初始化与值初始化兼容的类型”)但我已经放弃了。
相关讨论:
http://thread.gmane.org/gmane.comp.lib.qt.devel/8298
http://llvm.org/bugs/show_bug.cgi?id=14486
编辑
在构建推理过程时引用相关标准部分的答案将是理想的。
结论
因此,在 Nicol Bolas 给出了很好的回答之后,有趣的结论是 complex g = { 1, 2 } 是一个副本(它是复制初始化上下文),它不复制(复制列表初始化像直接列表初始化一样解析) ) 标准建议有一个复制操作 (12.6.1: ...and copy/move it into g)。
修复
【问题讨论】:
-
这是很多标准的报价。您的实际问题是什么?
-
"这是 c++11 标准的缺陷吗?"然后查看“原子问题”。在删除复制构造时,它看起来像引用 atomic
v = ATOMIC_VAR_INIT(5) 的冲突。 -
我认为这个问题可以简化为“复制列表初始化是否意味着复制初始化?”,举个简短的例子。
-
@KerrekSB 我有我的办法,我已经在给出的答案中提到了引号。
-
我认为this question 可能是相关的。