“X x = x = X();”在C++中是否合法?

7

我将这个缩小了:

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

请翻译为:

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

在我看来,这似乎是合法的。我不知道你为什么想这样做,但这是合法的吗?是否有需要这样做的情况(不包括int情况,我意识到那完全没有用)?


6
你意识到 y = A() 这行代码是在一个未初始化的变量上调用了 operator= 函数吗? - R. Martinho Fernandes
@R.MartinhoFernandes 不是。能否详细说明一下? - Luchian Grigore
6
你说我把这个(例子)简化成了(完全不同的例子),我不明白你的意思。 - Mr Lister
@MrLister,我的原始问题是是否允许像这样使用初始化列表 - x(x = new int())而不是像通常一样使用x(new int())。但是如果简化版本是合法的,那么原始版本也是合法的,对吧? - Luchian Grigore
我知道第二个例子是合法的(即使 int x = x++; 也是!),但不确定第一个或第三个。需要一些研究。成员的初始化器与创建新变量并不相同,这是我所知道的。 - Mr Lister
可能是使用自身作为引用构造对象?的重复问题。 - Bo Persson
4个回答

17

这要看你如何定义“合法”。它会被编译,但这并不意味着它一定能正常工作。

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

对于尚未初始化(其构造函数尚未被调用)的非POD类实例调用函数将导致未定义的行为。如果X是POD类型(或在C++11中是平凡的),那么它可以工作。但否则就不行。


为什么POD和非POD类型之间会有差别?我不熟悉标准的这一部分。你能引用一下吗? - Luchian Grigore
由于POD类型具有位拷贝语义,所以如此。 - R. Martinho Fernandes
1
@LuchianGrigore:当我说“POD类”时,我链接到那个问题是有原因的。你应该阅读一下那个问题。 - Nicol Bolas
调用未初始化的非POD类实例上的函数会产生未定义的行为。荒谬!即使使用了[标签:language-lawyer]标签,你也应该说行为只是根据标准而不被定义。 - curiousguy
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Nicol Bolas
显示剩余5条评论

10

这样的语法是合法的,但在运行时会导致未定义的行为。就像这样的语句:

X x = x = X();

第二个 = 是赋值操作符,它将值赋给一个未初始化的变量。(第一个 = 仅仅是语法上的复制初始化,表示后面的值被用于初始化;它不是赋值。)


1

这是合法的语法。X在其自身定义的范围内。你可能想要一个对象引用它自己的情况是循环链表,类似于:

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

Node empty( &empty };

这个空列表包含一个指向自身的虚拟节点。这既是明确定义的,也是有用的。请注意,我们获取了空的地址,即使Node是非POD类型并且尚未构造,这也是合法的。我认为允许像你的int m = m = 3;示例中那样的赋值并不直接有用,但是对于语言来说,很难允许我的而不允许你的。

要了解如何将其应用于成员构造函数,请考虑:

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

一旦名称在范围内,允许对其进行赋值和从中赋值也变得可能。


你的例子完全不同。 - Luchian Grigore
@LuchianGrigore 这个问题是:“是否有情况需要这样做(不是int类型的情况,我意识到那完全没用)?”其他答案讨论了合法性,但没有说为什么它可能有用。我的答案解决了问题的这一部分。问题承认其确切的例子是无用的;稍微不同的例子是不可避免的。我讨论了如何从我的示例到达问题中的示例(即,一旦名称在范围内,赋值也变得合法)。 - Brangdon
好的,但是编辑改变了整个答案。在原始答案中,没有用自身初始化的对象。 - Luchian Grigore
请查看编辑历史记录。答案中始终包含 Node empty( &empty };,其中对象 empty 用自身进行初始化。我的编辑附加了解释:“要了解这是如何实现的...”。但感谢您取消了负评。 - Brangdon
哦,对不起。被 pNext( pNext_ ) 误导了。 :) 你是对的,在这种情况下加1 :) - Luchian Grigore

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

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

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


你也不需要用C++写结构体,我只是前向声明了一下,这样大家就知道它是一个结构体。 - Luchian Grigore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接