在下面的代码片段中,调用mc.function1()成功,并将默认值传递给function1。
我想知道为什么Visual Studio不认为 *std::make_unique< SomeClass >()是临时对象。如果我将SomeClass()设置为默认值,那么Visual Studio会正确地将其捕获为编译时错误,因为它是一个临时对象,我们试图将其绑定到非常量引用。
为什么Visual Studio 2019将 *std::make_unique< SomeClass >()视为非临时对象?
根据C++ ISO标准,*std::make_unique< SomeClass >()是否被视为临时对象?
还是编译器只是对它宽容?
class SomeClass
{
};
class MyClass
{
public:
void function1 (SomeClass &obj = *std::make_unique<SomeClass>()) { }
//void function2 (SomeClass &obj = SomeClass()) { } //compile error
};
int main()
{
MyClass mc;
mc.function1();
}
下面的function1编译并执行良好。
void function1 (SomeClass &obj = *std::make_unique<SomeClass>()) { }
我认为它不应该编译,因为 *std::make_unique()是一个临时对象,它被绑定到非常量引用。但是它构建和运行良好。
1条答案
按热度按时间11dmarpk1#
一个对象是否可以被绑定到一个引用与它是否是一个临时对象无关。这纯粹是一个用来初始化引用的表达式的值类别是什么的问题。如果值类别是左值,那么左值引用可以被绑定到表达式引用的对象。
std::unique_ptr
的operator*
有一个左值引用作为返回类型。对一个返回左值引用的函数的函数调用是一个左值。所以一个左值引用可以绑定到*
的结果引用的对象。std::unique_ptr
在这里没有任何特殊之处。您可以编写自己的函数来实现它:现在你可以写了
不管
/*whatever*/
有什么值类别,引用现在都可以绑定到它。不能将右值绑定到非
const
左值引用的规则纯粹是为了保护你,因为大多数时候这样做在语义上是错误的,并且/或者有更清晰的替代方案(例如const
左值引用或右值引用)。如果你想忽略这种保护,C++不会阻止你。但是考虑一下你是否真的想这么做。即使你设法将一个引用绑定到一个临时对象,这通常也不会延长临时对象的生存期。例如,如果上面的
/*whatever*/
引用了一个临时对象,那么这个临时对象的生存期将在初始化引用的那一行之后结束。所以这个引用将立即悬空。类似地,在你的例子中,用
std::make_unique
创建的临时对象将只存在到函数调用结束。如果你将引用存储在其他地方或从函数返回它,它将是悬空的。那么,通过引用修改它有什么意义呢(非const
左值引用),如果调用者永远不能使用你存储到其中的值?它可以只是一个const
左值引用。