1

Context: Embedded programming and initializer list nuances, especially the one that I think should invoke the copy constructor.

Question: Will the instantiation of a class in another class's initializer list to initialize a value-held member variable invoke the copy constructor? Example provided below where TestClassCopy has a member variable TestMember held by value as opposed to pointer or reference. This cppreference page does not seem to cover this sufficiently in the examples provided.

Bonus question: Will a copy constructor invoked in an initializer list produce any time/space perf impact? Seems like a compiler should be able to optimize this away if the C++ spec allows.


Here's the code (build tested with the VS2015 toolchain):

TestMember.h (not showing TestMember.cpp for space reasons)

#pragma once

#include <stdint.h>

class TestMember {
public:
    TestMember(uint8_t);

private:
    uint8_t m_value;
};

TestClassCopy.h

#pragma once

#include "test_member.h"

class TestClassCopy {
public:
    TestClassCopy();
    virtual ~TestClassCopy();

private:
    TestMember m_member;
};

TestClassCopy.cpp

#include "test_class_copy.h"

TestClassCopy::TestClassCopy() :
    m_member(TestMember(255)) { // invokes copy constructor yes?
}

TestClassCopy::~TestClassCopy() {
}

For completeness, other things where I might be making assumptions I shouldn't:

For a member pointer to a TestMember, a 'new' in the initializer list and a 'delete' in the destructor should be sufficient.

For a member reference, my understanding is that there's even more nuance in that if the reference is passed into the constructor, you can just assign it (since lifetime is managed outside of the initializer list). However, if the TestMember is instantiated in the initializer list (into a reference), then that's a no-no since the TestMember temporary goes away after the initialization is complete.

TestMemberReference.h

#pragma once

class TestMember;

class TestClassReference {
public:
    TestClassReference();
    virtual ~TestClassReference();

private:
    TestMember& m_member;
};

TestMemberReference.cpp

#include "test_class_reference.h"

#include "test_member.h"

TestClassReference::TestClassReference() :
    m_member(TestMember(255)) { // ew, don't do this; TestMember temporary will go out of scope
}

TestClassReference::~TestClassReference() {
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • In your first example the [copy is elided](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization), there is no copy performed. – Cory Kramer Jul 25 '17 at 17:47
  • you could always put a print statement or a break point in the copy constructor – Austin_Anderson Jul 25 '17 at 17:53
  • @CoryKramer, perfect that's what I was looking for thank you. I guess this means you are stating 'yes, the copy constructor could be invoked but due to elision, it may or may not be depending on compiler optimization settings etc'. PS. If you want to create a full response, I can accept it as an answer. – azy.development Jul 25 '17 at 19:54
  • @Austin_Anderson, good point. I'll try that to see if my particular compiler actually performs copy elision. In any case, it seems that whether invoked or not, it's admissible behaviour. – azy.development Jul 25 '17 at 19:56

1 Answers1

0

This cppreference page does not seem to cover this sufficiently in the examples provided

that cppreference page says "Initializes the base or member named by class-or-identifier using direct initialization" and if you click that, you can read that, as of C++17,

if the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather that a temporary materialized from it, is used to initialize the destination object: see copy elision

so the answer is: in C++17 no copy constructor is called. Before C++17, a copy constructor could technically be called, but copy elision eliminated that call. You could still observe it, as proof, by compiling your example with g++ -fno-elide-constructors -O0 -std=c++14

Cubbi
  • 46,567
  • 13
  • 103
  • 169