Reputation: 56547
Consider this code:
#include <iostream>
using namespace std;
struct Foo {
public:
int _a{};
Foo(int a) : _a{a}
{
std::cout << "ctor" << std::endl;
}
Foo(const Foo &)
{
std::cout << "copy" << std::endl;
}
};
int main () {
Foo a{10};
Foo b = 10;
std::cout << b._a << std::endl;
}
When I compile with
g++ -std=c++11 -fno-elide-constructors test.cpp
the output is
ctor ctor copy 0
which is what I expect, since the in Foo b = 10
, 10
is implicitly constructed from int
, then b
is copy constructed from Foo
. Furthermore, my copy constructor doesn't do anything, so the member _a
remains 0
(as it is in-class-initialized).
However, when I use copy elision
g++ -std=c++11 test.cpp
the output is
ctor ctor 10
which is surprising to say the least. I understand that the copy constructor is elided here, but this is a serious side-effect (the fact that the member is once initialized to 0 and once to 10), as it affects the rest of the code path.
Is this behaviour normal?
Upvotes: 4
Views: 797
Reputation: 153810
The whole point of singling copy elision out as a on optimization in specific cases is to allow eliding side effects of copy construction. That is, yes, it expected that copy elision happens despite the copy constructor and/or the destructor having side effects.
If you don't want copy elision to happen in certain cases you'll need to arrange for it to be inhibited. In your specific case it is admittedly a bit annoying to inhibit copy elision but something like this should do the trick:
template <typename T>
T const& inhibit(T const& ref) {
return ref;
}
// ...
Foo b = inhibit<Foo>(10);
Upvotes: 4