“X x = x = X();”合法的 C++ 吗?

Is `X x = x = X();` legal C++?

提问人:Luchian Grigore 提问时间:3/26/2012 最后编辑:BenLuchian Grigore 更新时间:7/24/2012 访问量:564

问:

我减少了这个:

struct A
{
   int * x;
   A() : x( x = new int() )
   {
   }
};

到以下内容:

int m = m = 3;
//or
struct X;
//...
X x = x = X();

对我来说似乎是合法的。我不明白你为什么要这样做,但它合法吗?在某些情况下,您是否想这样做(不是这样,我意识到这完全没用)?int

C++ 语言律师

评论

6赞 R. Martinho Fernandes 3/26/2012
您是否意识到这是在调用未初始化的变量?y = A()operator=
0赞 Luchian Grigore 3/26/2012
@R.MartinhoFernandes no.想要扩张吗?
6赞 Mr Lister 3/26/2012
我不明白你说我把这个(例子)简化为(完全不同的例子)的重点。
0赞 Luchian Grigore 3/26/2012
@MrLister我最初的问题是是否允许使用这样的初始值设定项列表 - 而不是像您通常那样使用 。但是,如果简化版本是合法的,那么原始版本也是合法的,对吧?x( x = new int() )x(new int())
0赞 Mr Lister 3/26/2012
我知道第二个例子是合法的(甚至被证明是合法的!),但不确定第一个或第三个。需要一些研究。成员的初始值设定项与创建新变量不同,这就是我所知道的。int x = x++;

答:

10赞 James Kanze 3/26/2012 #1

这在语法上是合法的,但在运行时会导致未定义的行为。在这样的声明中:

X x = x = X();

第二个是赋值,它赋值给一个未初始化的变量。(第一种是简单的语法,表示后面的内容应该用于复制初始化;它不是赋值。==

17赞 Nicol Bolas 3/26/2012 #2

这取决于你如何定义“合法”。它将编译;这并不意味着它保证有效。

在执行完整语句之前,未初始化。它还不是 X。因此,执行意味着创建一个临时变量并调用未初始化的变量X x = ...xx = X()XX::operator=(const X&)x

在尚未初始化的非 POD 类实例上调用函数(尚未调用其构造函数)会产生未定义的行为。如果是 POD 类型(或在 C++11 中是微不足道的),那么它将起作用。但除此之外没有。X

评论

0赞 Luchian Grigore 3/26/2012
为什么 POD 和非 POD 类型之间存在差异?我不熟悉标准的那部分。你能提供报价吗?
0赞 R. Martinho Fernandes 3/26/2012
@LuchianGrigore 因为 POD 类型具有按位复制语义。
1赞 Nicol Bolas 3/26/2012
@LuchianGrigore:当我说“POD类”时,我与这个问题联系在一起是有原因的。你应该读一读。
0赞 curiousguy 7/22/2012
-1 用于重复 std 所说的内容。“在尚未初始化的非 POD 类实例上调用函数会产生未定义的行为。”荒谬!即使有 language-lawyer 标签,你也应该说行为只是没有根据标准来定义。
0赞 Nicol Bolas 7/22/2012
@curiousguy:“你应该说,行为只是没有按照标准来定义。标准是定义事物的东西。因此,根据定义,如果某物未定义,则相对于标准而言,它是未定义的。而“语言律师”标签的全部意义在于,你可以根据标准给出答案。这是暗示的。
0赞 Pillum 3/26/2012 #3
int m = m = 3;
//or
struct X;
//...
X x = x = X();

这是合法的(如果你定义了一个名为 X 的结构,但你的结构名为 A,你也不需要用 c++ 编写结构),但两者都是未定义的行为。

x(x = new int())是合法的,但也有未定义的行为。

评论

0赞 Luchian Grigore 3/26/2012
“此外,您不需要使用 C++ 编写结构”我只是转发了它,以便人们知道它是一个结构。
1赞 Brangdon 7/23/2012 #4

这是合法的语法。X 在其自身定义的范围内。您可能希望对象引用自身的情况是循环链表,其行如下:

struct Node {
    Node( Node *pNext_ ) : pNext( pNext_ ) {
    }
    // ...
    Node *pNext;
};

Node empty( &empty };

这个空列表由一个虚拟节点组成,该虚拟节点具有指向自身的链接。这既明确又有用。请注意,我们取 empty 的地址,即使 Node 是非 POD 并且尚未构建,这也是合法的。我不认为像你的例子那样允许赋值是直接有用的,但语言很难允许我的,也不允许你的赋值。int m = m = 3;

若要了解这如何延续到成员构造函数,请考虑:

struct A {
    Node list;
    A() : list( &list ) {}
}  

一旦名称在范围内,也可以允许与它进行分配。

评论

0赞 Luchian Grigore 7/23/2012
你的例子完全不同。
0赞 Brangdon 7/24/2012
@LuchianGrigore 问题是,其他答案讨论了合法性,但没有说明为什么它可能有用。我的回答解决了问题的这一部分。这个问题承认它的确切例子是无用的;一个稍微不同的例子是不可避免的。我讨论了如何从我的例子到问题中的例子(即,一旦名称在范围分配中也变得合法)。"Are there cases where you'd want to do this (not the int case, I realize that's completely useless)?"
0赞 Luchian Grigore 7/24/2012
好的,但是编辑改变了整个答案。在原始版本中,没有用自身初始化的对象。
0赞 Brangdon 7/25/2012
检查编辑历史记录。始终包含对象与自身初始化的答案。我的编辑附加了解释,“看看这是如何延续的......”。但感谢您删除反对票。Node empty( &empty };empty
0赞 Luchian Grigore 7/25/2012
哦,对了,对不起。被 .:)你是对的,在这种情况下+1 :)pNext( pNext_ )