C++ 是自初始化';A=A';允许?

C++ 是自初始化';A=A';允许?,c++,C++,此代码在复制构造函数中运行时失败。 但是编译器(MSVS2008)没有发出警告 你能解释一下(最好是引用标准)这个代码是非法的还是什么 我知道A=A;从一开始就不应该写, 但我在寻找一个理论背景 class A { public: A() :p(new int) { } A(const A& rv) { p = new int(*rv.p); } ~A() { delet

此代码在复制构造函数中运行时失败。
但是编译器(MSVS2008)没有发出警告

你能解释一下(最好是引用标准)这个代码是非法的还是什么

我知道A=A;从一开始就不应该写, 但我在寻找一个理论背景

 class A
 {
 public: 

    A()
    :p(new int)
    {
    }

    A(const A& rv)
    {
        p = new int(*rv.p);
    }

    ~A()
    {
        delete p;
    }


 private:

    int *p;
 };

 int main()
 {
    A a = a;
 }

您的代码调用的不是标准构造函数,而是复制构造函数,因此您正在访问未初始化的指针。

A=A绝对不应该被编写。但是
a=a
是可以写的。分配操作员必须检查
&rv==此
,如果是自复制,则不执行任何操作

哦,是的,您确实需要为类A编写赋值运算符。

根据标准(12.6.1[class.expl.init]),自初始化是完全合法的

因此,以下内容是合法的

A a = a;
您只需要编写副本构造函数来正确处理它

A(const A& rv)
{
    if(&rv == this) {
        p = new int(0);
        return;
    }

    p = new int(*rv.p);
}

编辑:根据注释更新代码。

关于自我分配的有趣阅读:


特别是,请注意与此问题相关的“Postscript#1”以及给出的一些答案。

标准中是否引用了关于这是否是编译时错误的内容?它确实不可能是编译时错误。以下是触发问题的两个条件:*复制构造函数从源对象取消引用指针。*您正在用对象本身初始化对象。这两个问题可能位于完全不同的编译单元中,编译器需要同时看到这两个条件才能标记错误。每个条件本身都不是问题,因此编译器没有理由抱怨。@JohnMcG:I disaggre。。。变量声明和初始化不能在不同的编译单元中。这显然没有任何意义。不幸的是,C++委员会从来没有想过这个问题(或者说它并不重要……)。你可以争辩说,编译器是标准共模的,你在这个问题上是对的,但我认为这是标准的一个错误。对不起,我现在已经修复了答案。不。赋值操作符可以被优化掉,取而代之的是复制构造;a=a?将调用的默认构造函数,然后调用::运算符=()。我怀疑它会被优化掉。Martin的观点是,检查赋值操作符中的自赋值可能是防止类似情况发生的必要条件,但这是不够的。因为分配可以优化到复制构造函数中,所以复制构造函数也需要考虑。好吧,“正确”-这取决于你的意图。这样,您将得到未初始化的对象。请记住,“a”在作为参数传递给其自己的副本构造函数时不会初始化。因此“A::p”是未定义的,此复制构造函数不会对其进行初始化。补充:关于标准的答复的第一部分是正确的,但我认为第二部分是可疑的。虽然在这里可以避免崩溃,但由于p未初始化,以后很可能会崩溃。更新了复制构造函数代码以将p初始化为有用的内容检查自复制仅在运算符=()中有意义,而在复制构造函数中没有意义。请看Fred Larson的答案。正如我从答案中了解到的,该代码是合法的。我应该添加一个断言还是如果(&rv==this)p=NULL;为了安全起见?有人在他们的代码中以任何方式处理这个问题吗?