2016-09-26 8 views
1

Для инициализации опорного элемента без ссылки на внешний объект передается конструктору вмещающий класс, метод завода может быть использован, например:разрушиться в членах ссылок инициализируются Factory Method

struct B 
{ 
    B() : a(new_a()) {} 
    // factory 
    a& new_a() 
    { 
     A* a = new A; 
     return *a; 
    } 
    A& a; 
}; 

Однако , конечно B::a не будет уничтожен, когда конец жизни B заканчивается, потому что это ссылка. Но нет доступа к B::a за пределами B. Так что это утечка памяти. Чтобы исправить это можно назвать A::~A() из B::~B()

B::~B() {a.~A();} 

Но я прочитал вручную вызов деструкторов было нет-нет, поэтому ввод вызова A::~A() в деструкторе B::~B() падает плоским, или делает это?

Есть ли более чистый раствор?

+5

Я думаю, вам нужно переосмыслить свой дизайн. Например, * почему * у вас есть ссылка? Разве у вас нет фактического экземпляра (что я действительно рекомендую)? Или указатель (или, скорее, умный указатель)? –

+0

'return * a;' разделяет указатель. 'a' завершается копией' new'ed 'A', но« новый »' A' просочился. – user4581301

+0

@ пользователь4581301 нет. 'new_a' возвращает ссылку (предполагается, что тип возвращаемого значения должен быть' A & 'not' a & ') и который привязывается непосредственно к' B :: a'. Нет копии. –

ответ

4

delete &a; в денструкторе B должен правильно выполнять работу, чтобы избежать утечки памяти.

Я бы рекомендовал, чтобы функция фабрики скорее должна была возвращать std::unique_ptr<A>. Или вы просто используете простой экземпляр A как член B.

1

Более чистым решением было бы избежать преобразования указателя в ссылку. Ссылка на элемент данных A& a; означает, что struct B не принадлежит объект, указанный a. Однако в вашем случае это происходит, и это создает путаницу.

Вы должны предпочесть ссылки (и необработанные указатели) для отношений, не связанных с собственностью, и интеллектуальных указателей или объектов ценности для владения отношениями.

Например, std::unique_ptr<A> a; Элемент данных здесь ясно показывает намерение собственности, а в качестве бонуса a будет автоматически освобождаться при уничтожении B. Вам даже не нужно ничего писать в деструкторе ~B().

В результате ваша new a() функция может быть записана следующим образом:

std::unique_ptr<A> new_a() { return {new A()}; }

В том, что вам не нужно писать new_a(). Стандартная библиотека C++ уже определяет для вас такую ​​функцию: std::make_unique.

+1

'unique_ptr' имеет явный конструктор, поэтому вам нужно сделать' return std :: unique_ptr {new A}; '(или' return std :: make_unique (); 'как вы сказали). –