Работает ли RVO с «новым»?

В этом случае срабатывает копирование? Другими словами, современные компиляторы с разрешением копирования избегают вызова какого-либо конструктора копирования здесь?

class BigObj{};

BigObj fun()
{
BigObj b;
return b;
}
int main()
{
BigObj *pb = new BigObj(fun());
}

Я стремлюсь сохранить объект в указателе. Объект возвращается функцией. Я хочу сохранить его без копирования.

Я не могу использовать с ++ 11

0

Решение

ИМО не совсем понятно, на что вы нацелены. Если вы хотите использовать динамическое распределение, тогда ваша функция должна просто:

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
1

Другие решения

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.

0

По вопросам рекламы [email protected]