初始化中的自我分配

时间:2014-04-11 08:31:25

标签: c++

从上一个问题Initialisation of static variable with itself开始,让我们考虑一下新的例子:

#include <iostream>

class B
{
  public:
    B()
    {
        std::cout << "B()" << std::endl;
        m = 17;
    }

    B(const B & o)
    {
        std::cout << "B(const B& o)" << std::endl;
        m = o.m;
    }
    B & operator=(const B & o)
    {
        std::cout << "B & operator=(const B & o)" << std::endl;
        m = o.m;
        return *this;
    }
    int m;
};

int main()
{
    B b  = b;
    std::cout << b.m << std::endl;
}

程序的输出是

B(const B& o)
1840828080

'b'在这里使用未初始化,因为它在复制构造函数中用于构造自身。它导致未初始化的变量'm',从而显示垃圾。为什么编译器不会在这里发出警告,'b'是未初始化的(而'int a = a'会产生这样的警告)。

Link to live example

3 个答案:

答案 0 :(得分:3)

因为它是未定义的行为,编译器可能会也可能不会发出任何警告!在这种情况下,编译器不要求提供诊断(警告/错误)。

并且您的代码调用未定义的行为,因为b(在=的右侧)未初始化(如您所知) - 读取其值会调用UB。它基本上与this one相同。

答案 1 :(得分:1)

-Weffc ++绝对不是答案!警告只是说,初始化应该进入初始化列表。如果你这样做,警告就会消失:

#include <iostream>

class B
{
  public:
    B() : m(17)
    {
        std::cout << "B()" << std::endl;
    }

    B(const B & o) : m(o.m)
    {
        std::cout << "B(const B& o)" << std::endl;
    }
    B & operator=(const B & o)
    {
        std::cout << "B & operator=(const B & o)" << std::endl;
        m = o.m;
        return *this;
    }
    int m;
};

int main()
{
    B b  = b;
    int i = i;

    std::cout << b.m << " " << i << std::endl;
}

live example处的编译器给出了简单变量i的警告,但没有给出类变量b的警告。 所以这个问题仍然没有答案 - 为什么编译器会警告一个简单的类型,而不是一个更复杂的类型呢?

答案 2 :(得分:0)

正如@Nawaz所述,@ kcm1700警告不是编译器的要求。

至于为什么此标记-weffc++似乎比-Wall -Wextra -pedantic更严格,请参阅在线文档:http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html

您可以从文档中看到:

  

以下-W ...选项不受-Wall的影响。

     

-Weffc ++(仅限C ++和Objective-C ++)警告Scott Meyers&#39;以及违反以下风格指南的行为?有效的C ++系列   书籍:定义复制构造函数和赋值运算符   具有动态分配内存的类。首选初始化   在构造函数中的赋值。有operator =返回引用   *这个。必须返回对象时,不要尝试返回引用。区分增量和前缀和后缀形式   减少运营商。永远不要过载&amp;&amp;,||,或。这个选项也   启用-Wnon-virtual-dtor,它也是有效的C ++之一   建议。然而,检查延长以警告缺乏   可访问的非多态基类中的虚析构函数。

     

选择此选项时,请注意标准库标题   不遵守所有这些准则;使用'grep -v'来过滤掉那些   警告。

因此,如果您添加-weffc++标志,那么它将生成所需的警告:

g++-4.8 -std=c++11 -Weffc++ -Wall -Wextra -pedantic main.cpp && ./a.out

main.cpp: In constructor 'B::B()':

main.cpp:6:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++]

     B()

     ^

main.cpp: In copy constructor 'B::B(const B&)':

main.cpp:12:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++]

     B(const B & o)

     ^

请参阅live example及相关信息:Easy way find uninitialized member variables

对于评论中的修改后的示例,clang会正确检测到这两个示例,请参阅:http://coliru.stacked-crooked.com/a/d1a55f347ee928behttp://coliru.stacked-crooked.com/a/9676797c7d155b81

输出结果为:

main.cpp:27:12: warning: variable 'b' is uninitialized when used within its own initialization [-Wuninitialized]

    B b  = b;

      ~    ^

1 warning generated.

不同的编译器在检测此类问题方面具有不同的能力。