В этом случае срабатывает копирование? Другими словами, современные компиляторы с разрешением копирования избегают вызова какого-либо конструктора копирования здесь?
class BigObj{};
BigObj fun()
{
BigObj b;
return b;
}
int main()
{
BigObj *pb = new BigObj(fun());
}
Я стремлюсь сохранить объект в указателе. Объект возвращается функцией. Я хочу сохранить его без копирования.
Я не могу использовать с ++ 11
ИМО не совсем понятно, на что вы нацелены. Если вы хотите использовать динамическое распределение, тогда ваша функция должна просто:
BigObj * fun()
{
return new BigObj;
}
int main()
{
BigObj *pb = fun();
}
… и избавь себя от неприятностей.
Вопреки предыдущей версии ответа оказалось, что компилятор может пропустить значительный объем работы, если он находится в статическом контексте, который можно тщательно проанализировать:
class C {
public:
C() {qDebug() << "C created";}
C(const C & o) { qDebug() << "C copied"; }
};
C foo() {
C c;
qDebug() << &c;
return c;
}
...
C c = C(foo()); // note that `C c = ` is also copy construction
qDebug() << &c;
Выходные данные проверяют, что оба экземпляра имеют один и тот же адрес, поэтому даже в локальном контексте экземпляр фактически не сохраняется в кадре стека foo
,
Изменение на:
C * cp = new C(foo());
qDebug() << cp;
к моему удивлению также выведите один и тот же адрес, опуская и копию по значению, и конструктор копирования. c
в foo
создается непосредственно в блоке памяти, выделенном new
,
В заключение, компилятор C ++ достаточно умен для анализа и выполнения всевозможных оптимизаций.
Отключение оптимизаций в первом и втором случае соответственно:
C created
0x28fd97
C copied
C copied
C copied
0x28fdeb
...
C created
0x28fd97
C copied
C copied
0x34fd00
RVO относится к числу тех вещей, которые разрешены стандартом, но не требуются специально. Тем не менее, большинство современных компиляторов (по крайней мере, с соответствующими настройками оптимизации) будут реализовывать это. Однако, если вы хотите получить гарантию, вам нужно прочитать документацию по вашему компилятору.
Так как цель в любом случае состоит в том, чтобы динамически выделить объект, я бы просто изменил пример, чтобы вызываемая функция выполняла динамическое распределение. Вместо (код ОП);
BigObj fun()
{
BigObj b;
// presumably the point of fun() is that some initialisation
// of b occurs here
return b;
}
int main()
{
BigObj *pb = new BigObj(fun());
}
Я бы просто использовал
BigObj *fun()
{
BigObj *b = new BigObj;
// presumably the point of fun() is that some initialisation
// of *b occurs here
return b;
}
int main()
{
BigObj *pb = fun();
}
и устранить потенциальное копирование BigObj
все вместе. Единственное, что копируется — это значение указателя. Таким образом, компилятор не полагается на наличие конструкторов перемещения C ++ 11 для оптимизации вышесказанного, поскольку он избегает ненужного создания и копирования объектов, поэтому это соответствует тому, что OP не должны использовать C ++ 11.
Очевидно, что в любом случае было бы целесообразно сопоставить использование оператора new с соответствующим оператором delete.