Okay, let's start by define a struct and have some discussion about it.
struct SimpleStruct
{
int myInts[4]
}
This is a simple struct. It's also meeting the criterias for being a POD as well as an aggregate.
In the C++98 era, the typical initialization of such struct would be:
SimpleStruct s = {{1, 2, 3, 4}};
In C++11, the list initialization was introduced. We can use the list initialization syntax, in this case the copy list initialization version, which will perform aggregate initialization, since
SimpleStruct
is an aggregate.SimpleStruct s = {{1, 2, 3, 4}};
The other form of list initialization, the direct list initialization, will also perform aggregate initialization. This syntax was not available in the C++98 era.
SimpleStruct s{{1, 2, 3, 4}};
Aggregate initialization typically performs a memberwise initialization. Let's look in memory, when the statement above has executed. Remember that
0xcc
is the opcode for debug break.0x00B5F9B0 00 00 00 00 5e ef 18 7b 74 60 26 7b cc cc cc cc ....^ï.{t`&{ÌÌÌÌ
0x00B5F9C0 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................
0x00B5F9D0 cc cc cc cc f4 f9 b5 00 03 32 43 00 01 00 00 00 ÌÌÌÌôùµ..2C.....
Before continuing with the copy/move construction, let's see what std::is_trivial
, std::is_standard_layout
and std:: is_pod
returns when taking SimpleStruct
as a template argument.int main()
{
std::cout << std::boolalpha;
std::cout << "SimpleStruct is trivial: " << std::is_trivial<SimpleStruct>::value << std::endl;
std::cout << "SimpleStruct is standard layout: " << std::is_standard_layout<SimpleStruct>::value << std::endl;
std::cout << "SimpleStruct is pod: " << std::is_pod<SimpleStruct>::value << std::endl;
}
SimpleStruct is trivial: true
SimpleStruct is standard layout: true
SimpleStruct is pod: true
Now. let's see what is happening when we want to copy an instance of
SimpleStruct
. Remember, since SimpleStruct
does not define any special member functions, all of them are implicitly defined, including the copy- and move- constructor.SimpleStruct s{{1, 2, 3, 4}};
SimpleStruct other{s};
Let's look into the memory.
0x00F3FBA0 bc fb f3 00 cc cc cc cc 01 00 00 00 02 00 00 00 .ûó.ÌÌÌÌ........
0x00F3FBB0 03 00 00 00 04 00 00 00 cc cc cc cc cc cc cc cc ........ÌÌÌÌÌÌÌÌ
0x00F3FBC0 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................
0x00F3FBD0 cc cc cc cc f4 fb f3 00 03 32 8d 00 01 00 00 00 ÌÌÌÌôûó..2......
Above, at
0x00F3FBC0
, whe have s
, and at 0x00F3FBA8
, we have other
.Finally, let's investigate the move construction.
SimpleStruct s{{1, 2, 3, 4}};
SimpleStruct other{std::move(s)};
std::move
on a single int would imply a copy and applying std::move
on a c-style array would imply a copy of the whole array.Let's look into the memory.
0x010FF6C0 cc cc cc cc 01 00 00 00 02 00 00 00 03 00 00 00 ÌÌÌÌ............
0x010FF6D0 04 00 00 00 cc cc cc cc cc cc cc cc 01 00 00 00 ....ÌÌÌÌÌÌÌÌ....
0x010FF6E0 02 00 00 00 03 00 00 00 04 00 00 00 cc cc cc cc ............ÌÌÌÌ
Above, at
0x010FF6DC
, we have s
, and at 0x010FF6C4
, we have other
.According to this StackOverflow post, which is discussing the 'c-style array in a struct/class scenario', we have this statement from the C++ standard:
if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
This is what we have seen above in the memory dumps.
You are welcome to leave comments, complaints or questions!
No comments:
Post a Comment