Это стандартная проблема, не бойтесь.
Во-первых, вы можете сохранить свой дизайн с небольшим изменением:
class A
{
public:
A(B& b): m_b(b) {}
private:
B& m_b;
};
Используя ссылку вместо константной ссылки, компилятор отклонит вызов конструктора А, сделанного с временным, потому что нельзя брать ссылку из временного.
Не существует (прямого) решения для фактического сохранения const
, поскольку, к сожалению, компиляторы принимают странную конструкцию &B()
, даже если это означает получение временного адреса (и они даже не стесняются сделать его указатель на неконстантный ...).
Существует ряд так называемых умных указателей. Базовый в STL называется std::auto_ptr
. Другой (известный) - boost::shared_ptr
.
Эти указатели называются умными, потому что они позволяют вам не беспокоиться (слишком много) об уничтожении объекта и фактически гарантируют вам, что он БУДЕТ уничтожен, и это правильно. Таким образом, вам никогда не придется беспокоиться о звонке delete
.
Одно предостережение: не используйте std::auto_ptr
. Это зверь, потому что у него неестественное поведение в отношении копирования.
std::auto_ptr<A> a(new A()); // Building
a->myMethod(); // Fine
std::auto_ptr<A> b = a; // Constructing b from a
b->myMethod(); // Fine
a->myMethod(); // ERROR (and usually crash)
Проблема в том, что копирование (с использованием конструкции копирования) или присвоение (с использованием оператора присваивания) означает передачу права собственности от скопированного на копирование ... ОЧЕНЬ СЮРПРИЗИН.
Если у вас есть доступ к готовящемуся стандарту, вы можете использовать std::unique_ptr
, очень похоже на автоматический указатель, за исключением плохого поведения: его нельзя скопировать или назначить.
В то же время, вы можете просто использовать boost::shared_ptr
или, возможно, std::tr1::shared_ptr
. Они несколько идентичны.
Они являются прекрасным примером указателей с подсчетом ссылок. И они умны в этом.
std::vector< boost::shared_ptr<A> > method()
{
boost::shared_ptr<A> a(new A()); // Create an `A` instance and a pointer to it
std::vector< boost::shared_ptr<A> > v;
v.push_back(a); // 2 references to the A instance
v.push_back(a); // 3 references to the A instance
return v;
} // a is destroyed, only 2 references now
void function()
{
std::vector< boost::shared_ptr<A> > w = method(); // 2 instances
w.erase(w.begin()); // remove w[0], 1 instance
} // w is destroyed, 0 instance
// upon dying, destroys A instance
Вот что означает подсчитанная ссылка: копия и ее оригинал указывают на один и тот же экземпляр, и они разделяют его права собственности. И до тех пор, пока один из них еще жив, экземпляр А существует, и последний из них погибает, поэтому вам не нужно об этом беспокоиться !!
Вы должны помнить, что они делят указатель. Если вы измените объект, используя один shared_ptr, все его родственники увидят это изменение. Вы можете сделать копию в обычном режиме с помощью указателей:
boost::shared_ptr<A> a(new A());
boost::shared_ptr<A> b(new A(*a)); // copies *a into *b, b has its own instance
Итак, подведем итог:
- не используйте
auto_ptr
, у вас будут неприятные сюрпризы
- используйте
unique_ptr
, если доступно, это более безопасная ставка, и с ней легче всего иметь дело
- используйте
share_ptr
в противном случае, но остерегайтесь семантики поверхностного копирования
Удачи!