【发布时间】:2016-05-20 16:36:37
【问题描述】:
鉴于此代码示例,关于传递给 S 的临时字符串的生命周期的规则是什么。
struct S
{
// [1] S(const std::string& str) : str_{str} {}
// [2] S(S&& other) : str_{std::move(other).str} {}
const std::string& str_;
};
S a{"foo"}; // direct-initialization
auto b = S{"bar"}; // copy-initialization with rvalue
std::string foobar{"foobar"};
auto c = S{foobar}; // copy-initialization with lvalue
const std::string& baz = "baz";
auto d = S{baz}; // copy-initialization with lvalue-ref to temporary
按照标准:
N4140 12.2 p5.1(在 N4296 中删除)
在构造函数的 ctor-initializer (12.6.2) 中,临时绑定到引用成员会一直持续到 构造函数退出。
N4296 12.6.2 p8
绑定到 mem-initializer 中的引用成员的临时表达式格式不正确。
因此,拥有像[1] 这样的用户定义构造函数绝对不是我们想要的。它甚至应该在最新的 C++14 中格式不正确(或者是吗?)gcc 和 clang 都没有警告过它。
它会随着直接聚合初始化而改变吗?我看起来在那种情况下,临时生命周期延长了。
现在关于复制初始化,Default move constructor and reference members 声明 [2] 是隐式生成的。鉴于移动可能会被省略,同样的规则是否适用于隐式生成的移动构造函数?
a, b, c, d 中的哪一个具有有效引用?
【问题讨论】:
-
聚合初始化的临时对象的生命周期延长也不例外,因此临时对象的生命周期将得到延长。这保证了在“直接初始化”案例中创建的临时对象有适当的生命周期。
-
你的意思是“移动可能会被忽略”?引用绑定不能省略,
str_直接绑定到other.str。 (std::move无效) -
@M.M 我的意思是大多数编译器将执行直接初始化,而不是使用移动构造函数。是的
std::move(other).str与other.str相同,用于引用,此处无效 -
由于CWG 1696,它是 C++14 后的(状态:DRWP),导致绑定临时对象到 mem-initializers 中的引用成员格式错误的更改。其实现状态在clang is "unknown"。不确定 gcc 是否存在这样的列表。
标签: c++ reference initialization aggregate temporary