表达式“new T”是否评估为右值或左值?

时间:2014-09-25 17:12:59

标签: c++ new-operator lvalue rvalue

我目前正在阅读本教程/对右值参考的解释:

http://thbecker.net/articles/rvalue_references/section_07.html

在第2段到最后一段中,作者提到" 工厂主体中T的复制构造函数的参数是左值"。他所指的代码是:

template<typename T, typename Arg> 
shared_ptr<T> factory(Arg const & arg)
{ 
  return shared_ptr<T>(new T(arg));
}

我意识到new T(arg)在堆上构造了一个T对象,但是返回的值并不是一个临时指针值,如果不使用它会丢失(导致内存泄漏),以及因此rvalue?

编辑:只是为了澄清,我知道在这个例子中没有内存泄漏。我只是意味着,如果指针值没有被使用,我们将无法访问构造的T对象,因此我们会得到内存泄漏。

4 个答案:

答案 0 :(得分:3)

简短的回答,我确定有人会写一个更长的,但是:

new为您提供了一个指针 rvalue new int = nullptr;无法编译,但有关要求左值的错误。

取消引用该指针会给你一个左值*(new int) = 5;将编译(这个天真的语句也会泄漏内存,因为指针丢失了,当然)。

复制构造函数接受引用,因此如果您有指向object的指针,则需要取消引用它。

如果丢失指针,则无法将其删除,因此不会被破坏,堆内存也不会被释放(直到程序退出并将内存返回给操作系统)。

如果你将指针放到其他可以取得它所有权的对象上,比如shared_ptr,那么你就不会丢失指针。另一个对象将根据其语义删除它,最迟当另一个对象(或者是共享所有权的最后一个对象,如同shared_ptr)本身被破坏时。

答案 1 :(得分:2)

这里的许多贡献者似乎对什么是价值类别感到困惑,有些人甚至建议shared_ptr&#34;存储左值&#34;,这根本没有意义。

Lvalue和rvalueness与什么东西&#34;返回&#34;无关。或者记忆中的物体状态;它是关于代码中表达式的状态。表达式是左值还是右值(或其他表达式)来自各种语言规则和结构。

简而言之,左值表达式是名称,其他所有内容都不是左值表达式。此规则的一个值得注意的例外是*ptr,其中ptr是指针类型,因为*ptr被定义为由于历史原因导致左值(除非涉及运算符重载)

现在,标准中没有明确建议new&#34;返回&#34; (评估)rvalue,因为该语句没有任何意义。 new计算指向新内存块的指针,根据语言规则,表达式new T是一个右值,因为它是rvalue的意思。

如果不写一本书,很难更好地解释这一点,但这就是它的关键。

  

我意识到新的T(arg)在堆上构造了一个T对象,但是返回的值并不是一个临时指针值,如果不使用它将会丢失(导致内存泄漏),以及因此rvalue?

是的,基本上。它是指向动态分配内存的指针这一事实完全无关紧要。

答案 2 :(得分:1)

返回new是prvalue而不是左值,因为你不能写:

 new T(arg) =  ....;   // not legal, so no lvalue

标准定义(§3.10):一个左值(历史上所谓,因为左值可能出现在赋值表达式的左侧)指定一个函数或一个对象。new的返回指定对象的地址,而不是对象本身。

如果将此值分配给指针a并取消引用该指针,或者即使您直接取消引用新的返回值,也可以将其设为左值:

*new T(arg) = ....;    //  valid, althoug you'd loose the address ! 
*a = ....;     // normal poitner dereferencing 

标准(第5.3.1 / 1节)对此进行了解释:一元*运算符执行间接:应用它的表达式应该是指向对象类型的指针,或者指向函数类型的指针,结果是一个左值,引用表达式指向的对象或函数。

重要提示:您的修改和shared_ptr

您的示例不会泄漏:shared_ptr<T>(new T(arg))创建一个共享指针来处理您新创建的对象,如果不再使用它将删除它。

两种可能性:

  • 返回共享指针在表达式中使用(例如作为临时共享指针或分配给另一个shared_ptr对象):复制对象并更新其使用计数以反映对其的实时引用数。没有泄漏!

  • 忽略重新调整的共享指针:返回的对象被销毁,其使用计数减少,并且由于未在别处使用,因此删除了对象。

答案 3 :(得分:1)

不幸的是,运营商及其操作数的价值类别是underspecified,这让我们不得不推断出价值类别。许多人假定除非明确指定,否则结果是prvalue。

我们可以通过尝试使用左边的new进行任务,并看到它不起作用并得出结论它不会产生左值但是我们仍然没有指定境。

我们可以凭经验确定code from Luc Danton answer here does

template<typename T>
struct value_category {
    // Or can be an integral or enum value
    static constexpr auto value = "prvalue";
};

template<typename T>
struct value_category<T&> {
    static constexpr auto value = "lvalue";
};

template<typename T>
struct value_category<T&&> {
    static constexpr auto value = "xvalue";
};

// Double parens for ensuring we inspect an expression,
// not an entity
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value

和结果:

std::cout << VALUE_CATEGORY( new int) << std::endl ;

是:

  

prvalue

使用演绎来肯定我们的结论。