How can I compel the MSVC compiler to elide stack-allocation of large temporary objects?

302 Views Asked by At

This question is not a duplicate of this one or other similar questions. This question is about clearing a struct after it has been initialized and used already.


Update

After reading the first few of your comments I would like to clarify my question:

  • How can I compel the MSVC compiler to elide the large stack allocation?

I've updated the title, text and the code below to clarify this.


I've recently started to compile my projects with the /GS, /sdl and /analyze compiler options. (Microsoft Visual C++ 2015) With these options, the compiler correctly warns about questionable code constructions. However, I've come across some warnings that I've always thought to be good C++ style.

Please have a look at the following example code:

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);
}

I've been told that the standard C++ way of clearing a struct is the following one:

ms = {};

With the /analyze option, the compiler warns about this in the following way (example):

C:\Dev\MDS\Proj\MDSCPV\Vaps_Common_lib\camber_radar.cpp:162: warning: C6262: Function uses '144400' bytes of stack: exceeds /analyze:stacksize '16384'.. This allocation was for a compiler-generated temporary for 'struct BitmapBuffer' at line 162. Consider moving some data to heap.

I think the following happens:

  • a temporary object is constructed on the stack
  • the temporary object is copied to the object variable

I would like to see something like the default initialization happening there. In my opinion the compiler should be able to optimize the stack-allocation away. But apparently (according to the warning) the compiler does not do this. My question is this: How can I compel the compiler to elide the stack-allocation? I have now started to replace these places with the following code:

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

There are 1 best solutions below

1
On

Since my_struct is trivially copyable, compilers should be able to place a memset call instead of creating a temporary and then assign it, but it is not mandatory.

A Placement new expression will solve your problem: it constructs an object at a preallocated address using the supplied constructor. For example, new(&ms) my_struct{} gives the same semantics as ms = {}. Should my_struct have a Non trivial Destructor, an explicit call to ms.~my_struct() must precede the placement new. For reference: new expression

I suggest to not use this technique in a normal fashion. It is kind of 'black magic' low level C++. Good compilers should optimize using memset.

By the way, the oh_my global variable doesn't allocate a temporary on the stack because it is Constant initialized at compile time.