C++ 初始化中的自赋值 从我的最后一个问题出发,让我们考虑以下新的例子: #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; }

C++ 初始化中的自赋值 从我的最后一个问题出发,让我们考虑以下新的例子: #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; },c++,C++,“b”在这里未初始化使用,因为它在复制构造函数中用于构造自身。它导致未初始化的变量'm',从而显示垃圾。为什么编译器在这里不警告“b”是未初始化使用的(而“int a=a”产生这样的警告) 因为它是未定义的行为,编译器可能会或不会给出任何警告!在这种情况下,编译器不需要提供诊断(警告/错误) 您的代码调用未定义的行为,因为b(在=的右侧)是未初始化的(正如您自己所知)-读取其值会调用UB。这与。的情况基本相同,因为它是未定义的行为,编译器可能会也可能不会给出任何警告!在这种情况下,编译器不需要提

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


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


您的代码调用未定义的行为,因为
b
(在
=
的右侧)是未初始化的(正如您自己所知)-读取其值会调用UB。这与。

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


您的代码调用未定义的行为,因为
b
(在
=
的右侧)是未初始化的(正如您自己所知)-读取其值会调用UB。这与@Nawaz所述的情况基本相同,@kcm1700警告不是编译器的要求

至于为什么这个标志
-weffc++
似乎比
-Wall-Wextra-pedantic更严格,请参见在线文档:

您可以从文档中看到:

以下是我们的。。。选项不受-Wall的影响

<> > WebFc++(C++和Objul-C++)警告Scott Meyers的“有效C++系列”违反以下风格指南 books:定义的复制构造函数和赋值运算符 具有动态分配内存的类。更喜欢初始化而不是 构造函数中的赋值。Have operator=返回对的引用 *这个。当必须返回对象时,不要尝试返回引用。区分前缀和后缀形式的增量和 减量运算符。切勿超载&、| |或、,。此选项也适用 启用Wnon虚拟Dor,这也是一个有效的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)

     ^
见和相关的:

对于您在注释中修改的示例,clang正确地检测了这两种情况,请参见:和

输出为:

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

    B b  = b;

      ~    ^

1 warning generated.

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

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

至于为什么这个标志
-weffc++
似乎比
-Wall-Wextra-pedantic更严格,请参见在线文档:

您可以从文档中看到:

以下是我们的。。。选项不受-Wall的影响

<> > WebFc++(C++和Objul-C++)警告Scott Meyers的“有效C++系列”违反以下风格指南 books:定义的复制构造函数和赋值运算符 具有动态分配内存的类。更喜欢初始化而不是 构造函数中的赋值。Have operator=返回对的引用 *这个。当必须返回对象时,不要尝试返回引用。区分前缀和后缀形式的增量和 减量运算符。切勿超载&、| |或、,。此选项也适用 启用Wnon虚拟Dor,这也是一个有效的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)

     ^
见和相关的:

对于您在注释中修改的示例,clang正确地检测了这两种情况,请参见:和

输出为:

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

    B b  = b;

      ~    ^

1 warning generated.

不同的编译器在检测此类问题时会有不同的能力。

-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;
}
#包括
B类
{
公众:
B():m(17)
{

std::cout-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;
}
#包括
B类
{
公众:
B():m(17)
{

std::cout您使用的是什么编译器/平台/操作系统,大多数编译器都有会引发这种错误的标志warning@EdChum他的实时示例显示了带有
-Wall
-Wextra
的g++4.8并没有对此发出警告。@JBL添加
-Weffc++
标志将生成:
main.cpp:6:5:警告:“B::m”应该在成员初始值中初始化自定义列表[-Weffc++]
请参见编译器不负责报告所有情况下的警告,甚至不可能。编译器只是尽力检测这些情况。您使用的是什么编译器/平台/操作系统,大多数编译器都有会引发此类警告的标志warning@EdChum他的实时示例显示了带有
-Wall
-Wextra
doe的g++4.8sn不对此发出警告。@JBL添加
-Weffc++
标志将生成:
main.cpp:6:5:警告:“B::m”应在成员初始化列表[-Weffc++]中初始化
参见编译器不负责报告所有情况下的警告,这甚至是不可能的。编译器只是尽力检测这些情况。当然,编译器不需要报告所有情况下的警告