Предположим, у нас есть класс, который выглядит следующим образом.Обеспечить безопасное использование класса, содержащего ссылку или необработанный указатель
class DoStuffWithRef
{
DoStuffWithRef(LargeObject& lo) : lo_(lo) {}
// a bunch of member functions, some of them useful
// [...]
private:
LargeObject& lo_;
};
Класс разработан таким образом, что единственный здравомыслящий использование, когда по крайней мере один другой субъект имеет право собственности, что lo_
ссылки на объект. Если код клиента использует класс надлежащим образом, нет необходимости в DoStuffWithRef
, чтобы иметь право собственности на LargeObject
.
Есть ли способ принудительно использовать это использование или сигнализировать об ошибке, если класс используется неправильно? Можно ли что-либо сделать, кроме документирования предполагаемого использования DoStuffWithRef
?
Например, автоматически сохраненный DoStuffWithRef
может ссылаться на автоматически сохраненный LargeObject
.
void foo()
{
LargeObject lo;
DoStuffWithRef dswr(lo);
// some code that makes use of the DoStuffWithRef instance
return;
}
Это основное использование я имею в виду, хотя возможны и другие случаи, когда кто-то может быть гарантировано, чтобы иметь право собственности.
Проблема заключается в том, что клиентский код очень может создать экземпляр DoStuffWithRef
, который в конечном итоге обернется ссылкой. Если никто не имеет права собственности на LargeObject
, на который ссылается DoStuffWithRef
, тогда возникает хаос, когда DoStuffWithRef
пытается получить доступ к LargeObject
. Хуже того, хаос может произойти только спустя много времени после того, как была допущена ошибка.
Когда это произошло в прошлом, я использовал boost::shared_ptr<>
вместо ссылки (это было в C++ 03). Это не совсем выражает семантику класса соответствующим образом. Предпосылка заключается в том, что DoStuffWithRef
не нуждается в собственности - он предназначен для работы с объектами, принадлежащими другим, и если никто другой не владеет этим объектом, то функциональность, предоставляемая DoStuffWithRef
, не имеет смысла. Предоставление права собственности на DoStuffWithRef
имеет излишние накладные расходы и обеспечивает совместную семантику владения. weak_ptr<>
также будет иметь неправильную семантику, потому что мы не должны спрашивать во время выполнения, если указатель действителен.
У меня никогда не было такого сценария в разделе, чувствительном к производительности, или в случае, когда совместное владение было значительным бременем, поэтому это просто не имело значения, но я бы хотел, чтобы я знал о способе аккуратного выражения это в C++. Расходы небольшие, но они также не нужны. Что еще более важно, shared_ptr<>
скроет неправильное использование класса. Если DoStuffWithRef
, модифицированный для использования shared_ptr<>
, является единственным оставшимся владельцем LargeObject
, тогда оборванная ссылка была предотвращена в краткосрочной перспективе, но код клиента заканчивается на неизведанной территории.
[Предложение для наименее умного указателя мира] (http://www.open-std.org/jtc1/sc22/wg21/docs /papers/2014/n4282.pdf), который будет включен в C++ 17. – user657267