Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const member stack vs heap

If I try to compile this code

struct A {
    const int j;
};
A a;

I'll get an expected error:

error: uninitialized const member in ‘struct A’

but, if I try to compile this one:

struct A {
    const int j;
};
A * a = new A();

I'll get a successful build.

The question is: why does new allocation allows creating a variable with const member without explicit constructor and stack allocation - doesn't ?

like image 605
borisbn Avatar asked Nov 29 '14 08:11

borisbn


People also ask

Is Const stored in stack?

'const' variable is stored on stack. 'const' is a compiler directive in "C". The compiler throws error when it comes across a statement changing 'const' variable.

Is stack memory faster than Heap?

The stack is faster because the access pattern makes it trivial to allocate and deallocate memory from it (a pointer/integer is simply incremented or decremented), while the heap has much more complex bookkeeping involved in an allocation or free.

What is Heap vs stack?

Heap memory is used by all the parts of the application whereas stack memory is used only by one thread of execution. Whenever an object is created, it's always stored in the Heap space and stack memory contains the reference to it.

What is stack and Heap in C++?

stack : stores local variables. heap : dynamic memory for programmer to allocate. data : stores global variables, separated into initialized and uninitialized. text : stores the code being executed.


2 Answers

It's not because of the heap allocation, but because of the parenthesis you use when allocating. If you do e.g.

A* a = new A;

it would also fail.

The reason it works when you add the parenthesis is because then your structure is value initialized, and for a POD-type like A value-initialization value-initializes each member, and the default value-initialization for int is zero.

That means it would probably work creating the variable on the stack as well, if you just add the value-initialization parenthesis:

A a = A(); // watch out for the http://en.wikipedia.org/wiki/Most_vexing_parse

Though that brings other potential problems, better use uniform initialization if you can (requies C++11):

A a{};
like image 71
Some programmer dude Avatar answered Oct 27 '22 11:10

Some programmer dude


This is ill-formed as of C++14. §12.1 [class.ctor] says that

4 A defaulted default constructor for class X is defined as deleted if:

  • [...]
  • any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer does not have a user-provided default constructor,
  • [...]

A default constructor is trivial if it is not user-provided and if:

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • no non-static data member of its class has a brace-or-equal-initializer, and
  • all the direct base classes of its class have trivial default constructors, and
  • for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

§8.5 [dcl.init] says in turn that

7 To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);
  • [...]

8 To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • [...]

The empty pair of parentheses results in value-initialization. The default constructor for A is defined as deleted per [class.ctor]/p4. Thus, by [dcl.init]/p8, value-initialization means default-initialization, and by p7 the initialization is ill-formed because the constructor is deleted.

The C++11 version actually allowed value-initialization in this context; it says for value-initialization that, among other things,

if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

Since by the definition above the default constructor is trivial (even though it is deleted), it is not actually called. This was considered a defect in the standard and the relevant wording was changed by CWG issue 1301.

Compiler vendors usually do implement defect resolutions, so this could be considered a bug in GCC 4.8 that's been fixed in 4.9.

like image 26
T.C. Avatar answered Oct 27 '22 11:10

T.C.