【问题标题】:C6001 with overloaded assignment operator带有重载赋值运算符的 C6001
【发布时间】:2021-01-11 21:43:39
【问题描述】:

这个简化的示例代码在静态分析下引发 C6001:

struct st_facade
{
    st_facade &operator=(const int new_value) { m_value = new_value; return *this;}

private:
    int m_value;
};

struct foo
{
    st_facade my_int;
};

void main()
{
    foo f;
    f.my_int= 0; // C6001: Using uninitialized memory 'f'.
}

我的理解是,之所以会引发此警告,是因为假设重载的赋值运算符可能正在读取未初始化的内存。但在这种情况下,我们并没有这样做——我们实际上是在初始化内存。

如何告诉编译器这里的赋值运算符没有使用任何未初始化的内存?我尝试使用几种不同的 SAL 注释来表达这一点,但没有任何效果。

在这种情况下,零初始化内存(即使用foo f{};st_facade my_int{};)不是正确的答案。在实际代码中,这样的初始化可能会产生不可接受的性能影响

[edit] 出于类似的原因,基于构造函数的初始化也不是正确的答案。我们需要这种类型在创建时未初始化;我们需要通知静态分析器赋值运算符执行初始化。

[编辑 2] 更一般地说,我们需要一种方法来告诉静态分析器“此方法初始化对象”,而无需实现构造函数或对类型的每个实例进行零初始化。

【问题讨论】:

  • re:“可能正在读取未初始化的内存”:也许某些类可能会根据第三个字段的值将传入值存储在两个不同字段之一中。在这种情况下,分析将正确识别出我们在读取第三个字段时正在访问未初始化的内存。 (尽管编译器无法在不执行比当前能力更全面的分析的情况下具体指向第三个字段)
  • 也许有一个(非显式)构造函数 st_facade(int) 并将其改为移动赋值 st_facade& operator=(st_facade&&) noexcept = default

标签: c++ static-analysis sal


【解决方案1】:

这就是 C++ 有构造函数的原因。

struct st_facade
{
    explicit st_facade(int value) 
        : m_value{ value } 
    {}
    
    st_facade &operator=(const int new_value) { m_value = new_value; return *this;}

private:
    int m_value;
};

struct foo
{
    explicit foo(int value)
        : my_int{ value }
    {}

    st_facade my_int;
};

int main()
{
    foo f{0};
}

【讨论】:

  • 或者只是在int m_value旁边添加`= 0;`
  • 2021 年我不应该留下这样的警告,但 PiotrNycz 的出色建议需要 C++11 或更高版本。
  • 零初始化和构造函数在这里反标。 “st_”前缀的语义包括“默认情况下未初始化此结构”。我确实需要一种方法来表明赋值运算符是只写的。
猜你喜欢
  • 2013-12-08
  • 2021-11-27
  • 1970-01-01
  • 2013-03-30
  • 2013-02-14
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
相关资源
最近更新 更多