提问人:Prasad Patil 提问时间:3/24/2023 最后编辑:Prasad Patil 更新时间:3/24/2023 访问量:221
std::make_unique 作为临时对象未绑定到 C++ 中的非常量引用的解决方法
std::make_unique as workaround for temporary object not binding to non const reference in C++
问:
在下面的代码片段中,调用 mc.function1() 成功,默认值传递给 function1。
我想知道 visual studio 如何不将 *std::make_unique< SomeClass >() 视为临时对象。其中,如果我将 SomeClass() 设置为默认值,那么 Visual Studio 会正确地将其捕获为编译时错误,因为它是我们试图绑定到非常量引用的临时对象。
为什么 Visual Studio 2019 将 *std::make_unique< SomeClass >() 视为非临时对象?
根据 ISO C++标准,*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() 是绑定到非常量引用的临时对象。但它构建和运行良好。
答:
对象是否可以绑定到引用与它是否为临时对象无关。这纯粹是用于初始化引用的表达式的值类别的问题。如果值类别为 lvalue,则可以将左值引用绑定到表达式引用的对象。
operator*
OF 具有左值引用作为返回类型。对返回左值引用的函数的函数调用是左值。因此,左值引用可以绑定到结果所引用的对象。std::unique_ptr
*
std::unique_ptr
在这里没有任何特别之处。您可以编写自己的函数来执行此操作:
template<typename T>
T& as_lvalue(T&& t) {
return t;
}
现在你可以写
SomeClass& x = as_lvalue(/*whatever*/);
无论哪个值类别具有什么值,引用现在都可以绑定到它。/*whatever*/
你不能将右值绑定到非左值引用的规则纯粹是为了保护你,因为大多数时候这样做在语义上是错误的,和/或者有更明确的替代方案(例如 左值引用或右值引用)。如果你想忽略这种保护,C++ 不会阻止你。const
const
但是考虑一下你是否真的想这样做。即使您设法将引用绑定到临时对象,这通常也不会延长临时对象的生存期。例如,如果上面引用的是一个临时对象,则该临时对象的生存期将在初始化引用的行之后结束。因此,引用将立即悬空。/*whatever*/
同样,在您的示例中,创建的临时对象将仅存在到函数调用结束。如果将引用存储在其他位置或从函数返回它,它将悬空。那么,如果调用者永远无法将存储的值使用到其中,那么能够通过引用(非左值引用)修改它有什么意义呢?它可以只是一个左值引用。std::make_unique
const
const
评论
std::unique_ptr::operator*
总是返回单对象变体的左值引用,而数组变体不存在。`
std::make_unique<SomeClass>()
std::make_unique
*std::make_unique<SomeClass>()
std::unqiue_ptr::operator*
评论
void function3 (const SomeClass &obj = SomeClass())
void function3 (const SomeClass &obj = {})