Как сделать хранилище данных явным в С++
При работе с указателями и ссылками на С++ иногда бывает трудно увидеть, имеет ли указатель право собственности на данные, на которые ссылаются, или если это просто временная ссылка. Например:
Instance* i = new Instance();
Instance* j = i;
Как можно понять, какой из двух указателей имеет право собственности на экземпляр? Другими словами, как четко указывать, на каком вызове будет вызываться указатель?
Примечание. В приведенном выше примере это не сложно понять, так как это очень короткий фрагмент кода. Однако, когда указатель дублируется и проходит много, это может стать неясным.
Ответы
Ответ 1
Вы не можете определить владельца, так как нет встроенного механизма, чтобы узнать, какой указатель владеет памятью, на которую указывает указатель.
Если вы действительно обеспокоены этим, вы всегда можете представить свое собственное соглашение об именах, например. через некоторое предварительное исправление к вашим именам переменных. Другими словами, это ваш код, который может дать вам эту информацию. Поскольку вы (и ваши коллеги) пишете код, вы всегда можете убедиться, что этот проект применяется во время реализации. Это, конечно, означает, что каждый должен следовать этим "правилам".
Это одна из причин, почему общее соглашение кодирования так важно. Таким образом, вы можете прочитать свой собственный и другой код людей и понять его.
Ответ 2
Во-первых, представляется излишним смешение использования ссылки для ссылки на данные, которые необходимо удалить. Вместо этого используйте указатель.
Во-вторых, если вы хотите указать принадлежность к объекту, используйте класс оболочки, который управляет правами собственности. Для этой цели существует auto_ptr
, хотя и имеет недостатки. (Они должны быть адресованы unique_ptr в следующей версии языка, хотя это вам сейчас не помогает).
В-третьих, в самых простых случаях (как можно чаще) не используйте кучу напрямую. Просто объявите локальный объект, например.
std::vector<int> v;
Это не останавливает передачу права собственности, когда вам нужно (используйте swap
).
Ответ 3
Вы можете использовать что-то вроде shared_ptr<>
для явного совместного владения. Если вы хотите поддерживать четкого владельца с другими указателями, не относящимися к собственнику, ссылаясь на один и тот же объект, вы можете использовать что-то вроде boost::scoped_ptr<>
для владеющего указателя и иметь typedef для указателей без прав:
typedef Instance* UnownedInstance_ptr; // or some better name
Это по крайней мере документирует намерение. Я не знаю, как далеко от головы, чтобы иметь умный тип указателя, который предотвращает возможность удаления содержащегося указателя и предотвращает копирование указателя в другой интеллектуальный указатель, который переходит в собственность (поскольку источник не имеет собственность, чтобы отдать), но это может быть интересный класс для представления этой политики.
Ответ 4
Для меня я бы пошел с венгерской нотой!
Джоэл расскажет вам остальное:
Нарушение неправильного кода
пример в вашем случае::
Instance* Owener_i = new Instance();
Instance* Observer_j = i;
.
.
.
.
.
delete Observer_j; // Wrong! not an Owner.
Ответ 5
Как указывали другие - используйте соглашение. Я использую необработанные указатели для переменных, не являющихся владельцами, и владелец обычно завернут в какой-то умный указатель (например, boost:: scoped_ptr) или даже не указатель на всех, кроме объекта, созданного в стеке.