LINUX.ORG.RU

Копирование объекта при возврате из функции(C++)


0

0

Столкнулся с этим нюансом при написании сложного noncopyable класса, привел к простому примеру(в конце)

Проблема вот в чем, мой класс должен быть noncopyable и никогда фактически не копироваться, НО при той реализации что снизу, получается такая ругатня:

rilium@rilium:~/spectra_lib$ g++ test.cpp -I headers/ headers/noncopyable.hpp: In copy constructor ‘A::A(const A&)’: headers/noncopyable.hpp:24: error: ‘spectra::noncopyable::noncopyable(const spectra::noncopyable&)’ is private test.cpp:7: error: within this context test.cpp: In function ‘A f()’: test.cpp:17: note: synthesized method ‘A::A(const A&)’ first required here

Однако если убрать наследование от spectra::noncopyable(полный аналог boost:noncopyable) и раскоментировать конструктор копирования, его вызов фактически не происходит, причем не только касательно этого тестового класса, но и для любого другого, если новый локальный объект инициализируется возвращаемым из функции(проверял с помощью g++ -S)

Соответственно вопрос, это баг или фича? Как мне корректно добиться желаемого поведения - чтобы отказ в компиляции происходил ТОЛЬКО когда конструктор копирования действительно должен быть вызван. И из интереса, в каких случаях это вообще так, что A f(); ... A a(f()); Требует фактического вызова конструктора копирования

test.cpp:

#include "noncopyable.hpp" #include <iostream>

using namespace std;

class A : private spectra::noncopyable { public: A() { cout << "Object created" << endl; } // A(const A&) { cout << "Const copy constructor" << endl; } ~A() { cout << "Object destroyed" << endl; } };

A f() { A a; return a; }

int main() { A b = f(); }

anonymous

#include "noncopyable.hpp"
#include <iostream>

using namespace std;

class A : private spectra::noncopyable
{
public:
	A()  { cout << "Object created" << endl; }
//	A(const A&) { cout << "Const copy constructor" << endl; }
	~A() { cout << "Object destroyed" << endl; }
};

A f()
{
	A a;
	return a;
}

int main()
{
	A b = f();
}

Прошу прощения за корявость форматирования первого поста :)


С уважением, Rilium.

anonymous
()

> Соответственно вопрос, это баг или фича?

AFAIK, это допустимая оптимизация.

> Как мне корректно добиться желаемого поведения - чтобы отказ в компиляции происходил ТОЛЬКО когда конструктор копирования действительно должен быть вызван.

А что не так с твоим вариантом?

> И из интереса, в каких случаях это вообще так, что A f(); ... A a(f())

Не понял, о чем ты спросил, но ответ наверняка есть в стандарте %)

tailgunner ★★★★★
()

То, что копирование не выполняется - это фича, типичный случай оптимизации. Место в стеке под возвращаемый объект располагается до сохранённого регистра IP, и благодаря этому после возврата из функции объект можно использовать как объявленный в блоке, из которого вызывалась функция.

Если нужно, чтобы объект не копировался, то его нужно в куче размещать (выделять память через new), и возвращать через указатель. Я обычно использую подсчёт ссылок и возвращаю Ref<Object> (вроде смартпоинтера, но с refcounting'ом).

anonymous
()
Ответ на: комментарий от tailgunner

Не совсем коректно сформулировал вопрос. Что такое RVO я знаю, в моем случае это даже не RVO, а NRVO, и в стандарте это оговорено(допустимость его использования).

Желаемое поведение: мой класс noncopyable, но может возвращаться функцией в тех случаях когда работает RVO или NRVO, как это правильно сделать?

Про баг это или фича, это что gcc ругается на мою конструкцию несмотря на то, что копирование там не требуется (он там однозначно может использовать NRVO).

anonymous
()
Ответ на: комментарий от anonymous

Мне кажется никак официально. Обязан тут класс поддерживать семмантику копирования.

placement_new ★★
()
Ответ на: комментарий от anonymous

скорее всего gcc проверяет синтаксическую корректность,
на этапе которой он определят что чтобы делать так,
должен быть конструктор копии,
а потом уж проводит ряд оптимизаций, в том числе исключение копирования при возврате из функции,

не совсем понятно зачем же возвращать объект по значению,
и в тоже время требовать некопируемости объекта.

fghj ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.