Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 表达式'new T'的计算结果是右值还是左值?_C++_New Operator_Lvalue_Rvalue - Fatal编程技术网

C++ 表达式'new T'的计算结果是右值还是左值?

C++ 表达式'new T'的计算结果是右值还是左值?,c++,new-operator,lvalue,rvalue,C++,New Operator,Lvalue,Rvalue,我目前正在阅读本教程/右值参考说明: 在第二段到最后一段中,作者提到“工厂主体中T的复制构造函数的参数是左值”。他所指的代码是: template<typename T, typename Arg> shared_ptr<T> factory(Arg const & arg) { return shared_ptr<T>(new T(arg)); } 模板 共享ptr工厂(参数常量和参数) { 返回共享的ptr(新的T(arg)); }

我目前正在阅读本教程/右值参考说明:

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

template<typename T, typename Arg> 
shared_ptr<T> factory(Arg const & arg)
{ 
  return shared_ptr<T>(new T(arg));
}
模板
共享ptr工厂(参数常量和参数)
{ 
返回共享的ptr(新的T(arg));
}
我意识到
newt(arg)
在堆上构造了一个T对象,但是返回的值不是一个临时指针值吗?如果不使用它,它会丢失(我猜这会导致内存泄漏),因此会产生一个右值


编辑:只是澄清一下,我知道在这个例子中不会有内存泄漏。我的意思是,如果没有使用指针值,我们将无法访问构造的T对象,因此我们将出现内存泄漏。

简短回答,我相信有人会写更长的,但是:

new
给你一个指针右值:
newint=nullptr编译失败,错误为需要左值

取消对该指针的引用会给出一个左值:
*(new int)=5
将编译(当然,由于指针丢失,这个幼稚语句也会泄漏内存)

复制构造函数接受引用,所以如果您有指向对象的指针,则需要取消引用它

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


如果将指针指向可以拥有它的其他对象,如
共享\u ptr
,则不会丢失指针。另一个对象将根据其语义删除它,最迟在另一个对象(或最后一个,在共享所有权的情况下,如
shared\u ptr
)本身被破坏时删除。

的返回是PR值而不是左值,因为您无法写入:

 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)对此进行了解释:一元
*
运算符执行间接寻址:应用该运算符的表达式应为指向对象类型的指针,或指向函数类型的指针,结果为引用表达式所指向的对象或函数的左值

重要提示:您的编辑和
共享\u ptr

您的示例不会泄漏:创建一个共享指针来处理新创建的对象,如果不再使用它,将删除它

两种可能性:

  • 在表达式中使用返回共享指针(例如,作为临时共享指针或分配给另一个共享\u ptr对象):复制对象并更新其使用计数以反映对该对象的实时引用数。不许泄露

  • 返回的共享指针将被忽略:返回的对象将被销毁,其使用计数将减少,并且由于它未在其他地方使用,您的对象将被删除


不幸的是,运算符及其操作数的值类别非常复杂,这使我们不得不推导值类别。许多人认为,除非明确指定,否则结果是一个PR值

通过尝试在作业左侧使用
new
,我们可以做出一个很有根据的猜测,看到它不起作用,并得出结论,它不会产生左值,但我们仍然处于未指定的领域

我们可以根据经验确定如下:

模板
结构值\类别{
//或可以是整数或枚举值
静态constexpr auto value=“prvalue”;
};
模板
结构值\类别{
静态constexpr auto value=“左值”;
};
模板
结构值\类别{
静态constexpr auto value=“xvalue”;
};
//双参数确保我们检查表达式,
//不是实体
#定义值\类别(expr)值\类别::值
结果是:

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

std::cout这里的许多贡献者似乎对什么是价值类别感到困惑,有些人甚至认为
shared\u ptr
“存储左值”,这毫无意义

左值和右值实际上与某些东西“返回”的内容或内存中对象的状态无关;这是关于代码中表达式的状态。一个表达式是左值还是右值(或其他任何一个)来自于各种语言规则和结构

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

现在,标准中没有明确建议
new
“返回”(计算结果)右值,因为该语句没有任何意义
new
的计算结果是指向新内存块的指针,根据语言规则,表达式
new T
是一个右值,因为右值就是这个意思

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

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

是的,基本上是这样。事实上
std::cout << VALUE_CATEGORY( new int) << std::endl ;