【问题标题】:default member value initialization is ignored in GCC默认成员值初始化在 GCC 中被忽略
【发布时间】:2021-12-28 23:12:46
【问题描述】:

我在下面的代码中提出了一个意外行为(据我个人所知),它不尊重默认的成员初始化值。我有一个单一参数赋值的承包商,它假设从赋值运算符构建类。我忘记使用正确的参数名称,最终遇到了这个问题(请参阅带有故意错误的单参数构造函数的行:

为什么我得到垃圾值而不是成员初始化值?

我自己的假设是因为模板类,00.0 不一样...但尝试使用 并得到同样的问题。

#include <iostream>
#include <concepts>


template <class T>
requires std::is_arithmetic_v<T>
class Complex
{
private:
    T re = 0;
    T im = 0;

public:

    Complex() {
        std::cout << "Complex: Default constructor" << std::endl;
    };

    Complex(T real) : re{re} { // should be re{real}, but why re{re} is not 0?
        std::cout << "Complex: Constructing from assignement!" << std::endl;
    };

    void setReal(T t) {
        re = t;
    }

    void setImag(const T& t) {
        im = t;
    }

    T real() const {
        return re;
    }

    T imag() const {
        return im;
    }

    Complex<T>& operator+=(const Complex<T> other) {
        re+= other.re;
        im+= other.im;
        return *this;
    }

    bool operator<(const Complex<T>& other) {
        return (re < other.re && im < other.im);
    }

};

int main() {
    
        Complex<double> cA;
         std::cout<< "cA=" << cA.real() << ", " << cA.imag() << "\n";

        Complex<double> cB = 1.0; // Should print "1.0, 0" but prints garbage
         std::cout<< "cB=" << cB.real() << ", " << cB.imag() << "\n";

    Complex<int> cC = 1;
    std::cout<< "cC=" << cC.real() << ", " << cC.imag() << "\n";
        
        return 0;
}

示例输出:

复数:默认构造函数 cA=0, 0 复杂:从赋值构造! cB=6.91942e-310, 0 复杂:从赋值构造! cC=4199661, 0

CompilerExplorer上的代码。

【问题讨论】:

    标签: c++ templates c++20


    【解决方案1】:
    Complex(T real) : re{re} { // should be re{real}, but why re{re} is not 0?
    

    如果您在构造函数中显式地为成员提供初始化程序,则此初始化程序替换默认成员初始化程序。在这种情况下根本不使用默认的成员初始化器。

    需要明确:默认成员初始化器不会在构造函数调用之前初始化成员。他们只是为构造函数的成员初始化器列表中未提及的成员“填充”初始化器。

    在您的情况下,re{re} 访问了超出其生命周期 (re) 的对象,从而导致未定义的行为。


    另外,作为旁注:Complex&lt;double&gt; cB = 1.0;Complex&lt;int&gt; cC = 1; 不是作业。两者都是带有初始化的声明。 = 不是赋值表达式的一部分,也不会像赋值那样调用 operator=。它们都是复制初始化,而Complex&lt;double&gt; cB(1.0);直接初始化

    这些初始化使用的构造函数Complex(T real) 称为转换构造函数

    【讨论】:

    • 感谢您提供的额外信息。我刚刚意识到 CLANG 产生了一个有意义的警告:warning: field 're' is uninitialized when used here
    • @SaeidYazdani GCC 也是如此,但您需要启用警告(在 GCC 和 Clang 中)。通常建议将-Wall -Wextra 用作基本默认值。在没有这些标记的情况下,Clang 会更加主动一些,显然是错误的。
    猜你喜欢
    • 2019-09-10
    • 2012-08-29
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    相关资源
    最近更新 更多