- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我无法理解为什么当周围有完美的转发构造函数时绑定(bind)到 const 引用参数的临时对象的生命周期会缩短。首先,我们了解绑定(bind)到引用参数的临时变量:它们持续到完整表达式:
A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call
但是我发现有些情况并非如此(或者我可能只是误解了完整表达式的含义)。让我们举一个简单的例子,首先我们定义一个对象,它有冗长的构造函数和析构函数:
struct A {
A(int &&) { cout << "create A" << endl; }
A(A&&) { cout << "move A" << endl; }
~A(){ cout << "kill A" << endl; }
};
还有一个对象包装器 B,它将用于引用折叠:
template <class T> struct B {
T value;
B() : value() { cout << "new B" << endl; }
B(const T &__a) : value(__a) { cout << "create B" << endl; }
B(const B &p) = default;
B(B && o) = default;
~B(){ cout << "kill B" << endl; };
};
我们现在可以使用我们的包装器来捕获对临时对象的引用并在函数调用中使用它们,如下所示:
void foo(B<const A&> a){ cout << "Using A" << endl; }
int main(){ foo( {123} ); }
上面的程序打印出我所期望的:
create A
create B
Using A
kill B
kill A
到目前为止一切顺利。现在让我们回到B
并为可转换类型添加一个完美的转发构造函数:
template <class T> struct B {
/* ... */
template <class U, class = typename enable_if<is_convertible<U, T>::value>::type>
B(U &&v) : value(std::forward<U>(v)) {
cout << "new forward initialized B" << endl;
}
};
现在再次编译相同的代码会得到:
create A
new forward initialized B
kill A
Using A
kill B
注意我们的 A
对象现在在使用之前就被杀死了,这很糟糕!为什么临时 not 的生命周期延长到 foo
的完整调用在这种情况下?此外,没有其他调用 A
的析构函数。 , 所以没有它的其他实例。
我可以看到两种可能的解释:
B(T &&v)
而不是 template <class U>B(U &&v)
解决问题。{123}
不是 foo( {123} )
的子表达式.交换 {123}
对于 A(123)
也解决了这个问题,这让我想知道大括号初始化器是否是完整表达式。有人可以澄清这里发生了什么吗?
这是否意味着在某些情况下向类添加转发构造函数可能会破坏向后兼容性,就像它对 B
所做的那样?
您可以找到完整代码 here ,另一个测试用例因引用字符串而崩溃。
最佳答案
为 U
推断的类型在调用 B<A const&>::B(U&&)
是int
,因此唯一可以延长生命周期的临时调用 foo
在 main
是一个纯右值 int
临时初始化为 123
.
成员(member)A const& value
绑定(bind)到临时 A
,但是A
在构造函数的 mem-initializer-list 中创建 B<A const&>::B(U&&)
所以它的生命周期只在成员初始化期间延长[class.temporary]/5:
— A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
请注意,mem-initializer-list 是 ctor-initializer 中冒号之后的部分:
template <class U, class = typename enable_if<is_convertible<U, T>::value>::type>
B(U &&v) : value(std::forward<U>(v)) {
^--- ctor-initializer
^--- reference member
^--- temporary A
这就是为什么 kill A
在 new forward initialized B
之后打印.
Does this mean that adding a forwarding constructor to a class could break backward compatibility in some cases, like it did for
B
?
是的。在这种情况下,很难理解为什么需要转发构造函数;如果您有一个可以绑定(bind)临时对象的引用成员,那肯定是危险的。
关于c++ - 临时生命周期和完美的转发构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26484734/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!