D3D_SHADER_MACRO initialization, why does this work?

Started by
3 comments, last by jpetrie 7 years, 5 months ago
Hi,
I'm trying to wrap my head around initializer lists and initializing objects in my code.
Now there's one situation which does what I expect, but I'd like to understand why:

D3D_SHADER_MACRO *myDefines = new D3D_SHADER_MACRO[2]();

What I believe it does is set both LPCSTR members of both the d3d shader macro objects to NULL/nullptr (because of the () at the end).
Which is exactly what I aim for. But why does this work, I cannot find information that this d3d shader macro object has a default constructor. Or is it something else I'm not seeing/understanding. My goal is to initialize them to null(prr) at creation to prevent additional manually assigning the LPCSTR's to nullptr.

Any help is appreciated.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement
That code calls the default constructor. If they don't have one, thr members are uninitialised.

Do you even need to use new here? The easiest way would be:
D3D_SHADER_MACRO myDefines[2] = {};

The topic of initialization is covered in section 8.5 of the C++ standard, which I believe I referred you to in the chat, although that may have been after you posted this.

The standard says that "an object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized." Your initializer meets that form, and thus is value-initialized. The standard further says that "to value-initialize an object of type T means... if T is an array type, then each element is value-initialized." Thus, every element of myDefines is value-initialized.

The standard further describes value-initialization for other types T: "if T is a (possibly cv-qualified) class type with either no default constructor, or a default constructor that was user-defined or deleted, the object is default-initialized." So every element of myDefines is actually default-initialized.

Finally the standard says that "to default-initialize an object of type T means... no initialization is performed." This description applies only if T is not an array type (D3D_SHADER_MACRO is not) and if T has no applicable constructors (it has none).

Thus, your array elements are left in an uninitialized, indeterminate state. It likely appears to work because your compile zero-initializes in debug mode, or similar.

Thanks.

@Hodgman: here's some more code to give you a better context, why I use a pointer:


struct C_SHADER_DEFINE
{
	std::string Name;
	std::string Definition;
}


// shaderpack class definition

std::vector<C_SHADER_DEFINE> mDefines;

// the memory allocation, when copying mDefines to local scope defines
// note; needed in local scope because the D3D Shader macro has LPCSTR's, which won't "stay around"

D3D_SHADER_MACRO *defines = new D3D_SHADER_MACRO[1]();
if((int)mDefines.size() > 0) defines = new D3D_SHADER_MACRO[(int)mDefines.size()+1];

// next: copy the mDefines (strings) to define (LPCSTR)
for(size_t i=0;i<mDefines.size();++i) defines[i] = { mDefines[i].Name, mDefines[i].Definition };

// last shader macro needs to be NULL/NULL
defines[(int)mDefines.size()] = { nullptr, nullptr };		// 2 LPCSTR's, name and definition

@Josh: thanks, that was definately related (on the chat), I didn't link your alias here with 'josh' on Discord/ the chat (but it sounds very logical :))

I'll have to dig into that chapter (8.5) then and do some good reading, I thought I got it, but I clearly don't.

What I understand now is that assigning a value at creation, is called initialization, and using () is called value-initialization. I guess this also goes for { .... } initialization, but there you always pass explicit values. In the case of an array and () then all elements are value initialized.

With value initialization on a type that has a default contructor, that would be called now. Now D3D_SHADER_MACRO does not have a (default) constructor, so the elements in the array are 'default initialized' (instead of the default constructor): which means that no initialization is done, because there's now 'default' for the D3D_SHADER_MACRO type.

From this I understand that this would be a better way to go (without taking the risk of undefined memory):


D3D_SHADER_MACRO *defines = new D3D_SHADER[1];
defines[0] = { nullptr, nullptr };

// rest of the earlier code paste

We also talked about value initialization through a initializer list in a class constructor.

I would think that there's a relation between this and the above.

For example, a class member of type bool called 'myMember' could be in the initializer list like this:


// option 1
myClass::myClass() : myMember()

// option 2
myClass::myClass() : myMember(false)

If I apply the theory above, in option 1 I'm tryinig to initialize using (), I would expect that a default constructor would be called. Which in this case (type bool) doesn't exist. Maybe if I read chapter 8.5 I could explain why option 1 and 2 both work. But from what I understand above, I'd say that only option 2 would be correct/working.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

It seems that all of that code from the definition of "defines" on can be replaced with, more or less, something like:


std::vector<D3D_SHADER_MACRO> defines;
defines.reserve(mDefines.size());
for (const C_SHADER_DEFINE& define : mDefines) {
  defines.emplace_back(mDefines[i].Name, mDefines[i].Definition);
}

This has the side-effect of removing your memory leak in the allocation of defines.

If I apply the theory above, in option 1 I'm tryinig to initialize using (), I would expect that a default constructor would be called. Which in this case (type bool) doesn't exist. Maybe if I read chapter 8.5 I could explain why option 1 and 2 both work. But from what I understand above, I'd say that only option 2 would be correct/working.

Both work here, because () is value-initialization, which falls back to zero-initialization in this case.

This topic is closed to new replies.

Advertisement