Недавно у меня была следующая ошибка памяти , которую легко обнаружить, но ее сложнее обнаружить в более сложном коде:
class Foo : public IFoo {
const Bar& bar_;
public:
Foo(const Bar& bar) : bar_(bar) {
}
void test() {
// access bar_ here
}
};
int baz() {
IFoo* foo = NULL;
if(whatever) {
Bar bar;
foo = new Foo(bar);
}
else {
// create other foo's
}
foo->test(); // segmentation fault
}
Ошибка в том, что Bar
немедленно выходит из области видимости, уничтожается и затем используется в foo->test()
. Одним из решений является создание Bar
в куче, используя Bar* bar = new Bar()
. Однако я не люблю этого делать, потому что мне нужно держать указатель Bar* bar
на верхнем уровне, чтобы я мог получить к нему доступ и delete
в конце, даже если Bar
является чем-то специфичным для этот конкретный кодовый блок if(whatever){}
.
Другое решение - boost::shared_ptr<Bar>
, но я не могу просто написать это:
if(whatever) {
boost::shared_ptr<Bar> bar(new Bar());
foo = new Foo(*bar);
}
, поскольку shared_ptr
сразу же выходит из области видимости, уничтожая содержащийся объект.
Короче говоря, чтобы избавиться от этой проблемы, я должен использовать shared_ptr
везде , в Foo
в качестве переменной-члена, в конструкторе Foo
и т. Д. чтобы устранить эти проблемы в целом, все мои API и т. д. должны использовать shared_ptr
, что довольно уродливо. Но правильно ли это делать? До сих пор я использовал его иногда для создания объектов с подсчетом ссылок, но я сохранил свои API чистыми от shared_ptr
. Как вы справляетесь с этой проблемой: когда вы используете shared_ptr
, вы должны использовать его везде ?
(Кроме того, если вы используете эти указатели с подсчетом ссылок, вам следует начать беспокоиться о том, действительно ли вы хотите shared_ptr
или, скорее, weak_ptr
и т. Д.)
И что бы я использовал в качестве эквивалента Foo(const Bar& bar)
? Foo(const shared_ptr<const Bar> bar)
?
Другой вариант, конечно, это добавить подсчет ссылок внутри Bar
и других объектов самостоятельно, используя pimpl
и свои собственные счетчики, но это становится слишком утомительным, как правило.