1

在此代码片段中,Init() 函数充当按需初始化程序,用于填充结构的所有成员变量。这样做是为了避免调用堆栈上大型数组的所有成员的默认构造函数:

struct Foo {
    int m_Member;
    void Init(int i);
};

void Foo::Init(int i) {
    m_Member = i;
    // Many other members initialized here.
}

void SomeFunction(int n) {
    Foo buffer[64];
    assert(n <= 64);
    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        buffer[i].Init(i * 3);
    }
    // Use buffer[0] - buffer[n-1] somehow.
}

这会在 VS2012 中使用 /analyze 触发静态分析错误:

warning C6001: Using uninitialized memory 'buffer'.: Lines: 17, 19, 20

我正在寻找一种方法来注释 Foo::Init() 以便不会发生此警告。还有很多其他方法可以消除警告,包括:

  • 添加一个空的构造函数
  • 将 Init() 移至构造函数并在循环中调用placement new

但我想避免改变代码的结构。

我尝试了以下注释但没有成功:

void _At_(this, _Out_) Init();

此语法被接受,但仅将警告更改为:

warning C6001: Using uninitialized memory 'buffer'.: Lines: 18, 20, 21
warning C6001: Using uninitialized memory 'buffer[BYTE:0]'.: Lines: 18, 20, 21

有谁知道我如何向静态分析引擎声明这个 Init() 函数的意图?

4

4 回答 4

0

你的问题有点难以捉摸。您已经展示SomeFunction了服用int,但需要方法Init或构造函数的注释。

显示的警告绝对正确,assert不会隐藏警告。您需要 putif检查是否n大于64并重置n(或执行其他操作,但不要循环 when n>=64)。

对于注释,您需要使用__in_bcount或类似的替代方法。一个例子:

bool SetBuffer(__in_bcount(8) const char* sBuffer);

这说 sBuffer 是8 字节(不是元素)。

您可以阅读这篇文章以获取更多信息。

于 2013-01-26T05:20:16.987 回答
0

添加一个额外的助手太丑了?

struct Foo {
    int m_Member;
    void Init(int i);
};

void Foo::Init(int i) {
    m_Member = i;
    // Many other members initialized here.
}

void Initialize(__in_bcount(sizeof(Foo) * n) Foo* buffer, int n) {
    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        buffer[i].Init(i * 3);
    }
}

void SomeFunction(int n) {
    Foo buffer[64];
    assert(n <= 64);
    Initialize(buffer, n);
    // Use buffer[0] - buffer[n-1] somehow.
}
于 2013-01-28T18:57:41.200 回答
0

我通过实现一个函数来索引数组找到了解决方法。我将返回值标记为无效,以便这个新函数仅在返回值仅用于初始化的特定情况下转义未初始化值检查。我只在 VS2017 中测试过这个。

#define _Ret_invalid_                     _SAL2_Source_(_Ret_invalid_, (), _Ret1_impl_(__notvalid_impl))

template <typename T>
_Ret_invalid_ T& UninitialzedIndex(T* pt, int index)
{
   return pt[index];
}

然后,在索引值的地方,我调用 UninitialzedIndex 而不是 operator[]

void SomeFunction(int n) {
    Foo buffer[64];
    if (n <= 64)
      return;

    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        UninitialzedIndex(buffer, i).Init(i * 3);
    }
    // Use buffer[0] - buffer[n-1] somehow.
}
于 2018-04-27T16:03:16.930 回答
-2

只需添加一个默认构造函数(调用 Init())。那有什么问题?

[编辑] 根本问题不是如何欺骗静态分析器或编译器。这是如何强制您不要让 foo 处于未初始化状态。添加默认构造函数没有任何问题。我想说不这样做的愿望会带来风险。

也许某些客户会使用构造不佳的 foo 类(在您编写它很久之后,在您离开之后很久),也许他们会忘记调用 .Init() ?然后怎样呢?他们将留下未初始化的数据。

如果您希望强制执行该规则,那么再多的静态分析也无济于事。

在安装屋顶之前,请先处理好地基。

于 2013-01-26T00:14:21.550 回答