В соответствии с запросом от ОП, здесь приведена адаптированная версия моего комментария
Мне на самом деле было интересно то же самое (особенно с тех пор, как elision copyстандарт не является «обязательным») , поэтому я быстро протестировал его в онлайн-компиляторе, заменив std::vector
структурой Widget:
struct Widget
{
int val = 0;
Widget() { printf("default ctor\n"); }
Widget(const Widget&) { printf("copy ctor\n"); }
Widget(Widget&&) { printf("move ctor\n"); }
Widget& operator=(const Widget&) { printf("copy assign\n"); return *this; }
Widget& operator=(Widget&&) { printf("move assign\n"); return *this; }
~Widget() { printf("dtor\n"); }
void method(int)
{
printf("method\n");
}
};
V1, используя build_vector()
: http://coliru.stacked -crooked.com / a / 5e55efe46bfe32f5
#include <cstdio>
#include <array>
#include <cstdlib>
using std::array;
struct Widget
{
int val = 0;
Widget() { printf("default ctor\n"); }
Widget(const Widget&) { printf("copy ctor\n"); }
Widget(Widget&&) { printf("move ctor\n"); }
Widget& operator=(const Widget&) { printf("copy assign\n"); return *this; }
Widget& operator=(Widget&&) { printf("move assign\n"); return *this; }
~Widget() { printf("dtor\n"); }
void method(int)
{
printf("method\n");
}
};
bool some_condition(int x)
{
return (x % 2) == 0;
}
array<int, 3> something()
{
return {{1,2,3}};
}
Widget build_vector(int n)
{
if (some_condition(n)) return {};
Widget out;
for(int x : something())
{
out.method(x);
}
return out;
}
int main(int argc, char* argv[])
{
if (argc != 2)
{
return -1;
}
const int x = atoi(argv[1]);
printf("call build_vector\n");
Widget w = build_vector(x);
printf("end of call\n");
return w.val;
}
Выход V1
call build_vector
default ctor
method
method
method
move ctor
dtor
end of call
dtor
V2 с использованием nrvo_friendly_build_vector()
: http://coliru.stacked -crooked.com / a / 51b036c66e993d62
#include <cstdio>
#include <array>
#include <cstdlib>
using std::array;
struct Widget
{
int val = 0;
Widget() { printf("default ctor\n"); }
Widget(const Widget&) { printf("copy ctor\n"); }
Widget(Widget&&) { printf("move ctor\n"); }
Widget& operator=(const Widget&) { printf("copy assign\n"); return *this; }
Widget& operator=(Widget&&) { printf("move assign\n"); return *this; }
~Widget() { printf("dtor\n"); }
void method(int)
{
printf("method\n");
}
};
bool some_condition(int x)
{
return (x % 2) == 0;
}
array<int, 3> something()
{
return {{1,2,3}};
}
Widget nrvo_friendly_build_vector(int n)
{
Widget out;
if (some_condition(n)) return out;
for(int x : something())
{
out.method(x);
}
return out;
}
int main(int argc, char* argv[])
{
if (argc != 2)
{
return -1;
}
const int x = atoi(argv[1]);
printf("call nrvo_friendly_build_vector\n");
Widget w = nrvo_friendly_build_vector(x);
printf("end of call\n");
return w.val;
}
Выход V2
call nrvo_friendly_build_vector
default ctor
method
method
method
end of call
dtor
Как вы можете видеть, в данном конкретном случае (побочные эффекты от создания структуры не видны по некоторому условию) , V1 вызывает конструктор перемещения, если some_condition()
имеет значение false (по крайней мере, вclang и gcc, используя -std=c++11
и -O2
в Coliru )
Более того, как вы заметили , похоже, происходит то же самое поведениена -O3
.
HTH
ps: при изучении возможности копирования вы можете To Abseil ToW # 11 интересно;)