【问题标题】:How can I compel the MSVC compiler to elide stack-allocation of large temporary objects?如何强制 MSVC 编译器省略大型临时对象的堆栈分配?
【发布时间】:2019-05-12 12:33:37
【问题描述】:

此问题与this one 或其他类似问题不重复。这个问题是关于清除一个结构它已经被初始化和使用过。


更新

在阅读了您的前几篇 cmets 之后,我想澄清一下我的问题:

  • 如何强制 MSVC 编译器忽略大堆栈分配?

我已经更新了标题、文本和下面的代码来澄清这一点。


我最近开始使用/GS/sdl/analyze 编译器选项编译我的项目。 (Microsoft Visual C++ 2015)使用这些选项,编译器可以正确警告有问题的代码结构。但是,我遇到了一些我一直认为是好的 C++ 风格的警告。

请看下面的示例代码:

struct my_struct {
    char  large_member[64000];
};

void do_something_else(my_struct & ms)
{
    // the intent of the next line is to "clear" the ms object
    ms = {};  // <-- here the compiler claims the large stack allocation

   // ... do some more work with ms
}

my_struct oh_my = {}; // construction, apparently no large stack allocation

int main()
{ 
    // ...
    // do something with the oh_my object
    // 

    do_something_else(oh_my);
}

有人告诉我,清除结构的标准 C++ 方法如下:

ms = {};

使用/analyze 选项,编译器会通过以下方式发出警告(示例):

C:\Dev\MDS\Proj\MDSCPV\Vaps_Common_lib\camber_radar.cpp:162:警告:C6262:函数使用堆栈的 '144400' 字节:超过 /analyze:stacksize '16384'.. 此分配用于编译器在第 162 行为“struct BitmapBuffer”生成临时文件。考虑将一些数据移动到堆中。

我认为会发生以下情况:

  • 在堆栈上构造了一个临时对象
  • 临时对象被复制到对象变量中

我希望看到类似默认初始化的情况。在我看来,编译器应该能够优化堆栈分配。但显然(根据警告)编译器没有这样做。 我的问题是:如何强制编译器忽略堆栈分配? 我现在已经开始用以下代码替换这些地方:

std::memset(&ms, 0, sizeof(ms));

【问题讨论】:

  • 在发布模式(开启优化)下构建时是否也会收到警告?
  • 是的,我在发布模式下得到了它。我正在使用/GS /analyze 选项进行发布构建。 (/GS/sdl 在某种程度上相互排斥)
  • 对我来说似乎很好。您在堆栈上分配了两个至少 64000 字节的结构,鉴于阈值是 16384 字节,编译器有权抱怨。
  • @user10605163,“不能省略”是什么意思? GCC 和 Clang 为该行生成一个 memset 调用:godbolt.org/z/G6CQO_
  • @Evg 是的,我不知道我在想什么。

标签: c++ visual-c++ initialization stack-allocation


【解决方案1】:

由于my_struct可轻松复制,编译器应该能够发出memset 调用,而不是创建一个临时的然后分配它,但这不是强制性的。

Placement new 表达式 将解决您的问题:它使用提供的构造函数在预先分配的地址构造一个对象。例如,new(&amp;ms) my_struct{} 给出与ms = {} 相同的语义。如果my_struct 有一个非平凡的析构函数,那么对ms.~my_struct() 的显式调用必须在放置new 之前。供参考:new expression

我建议不要以正常方式使用此技术。这是一种“黑魔法”低级 C++。好的编译器应该使用memset进行优化。

顺便说一下,oh_my 全局变量不会在堆栈上分配临时变量,因为它在编译时是常量初始化的

【讨论】:

  • 显然 Microsoft Visual C++ 2015 不是一个好的编译器
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 2014-03-20
  • 1970-01-01
  • 2012-07-18
  • 2021-12-25
相关资源
最近更新 更多