Предположим, у нас есть класс, который выглядит следующим образом.
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
затем в течение короткого периода времени оборванная ссылка была предотвращена, но код клиента оказался на неизведанной территории.
DoStuffWithRef в противном случае с состоянием? Если нет, то похоже, что это набор утилитарных функций. Ссылка на LargeObject также может быть передана в качестве аргумента каждой функции. Это также решает вопрос о собственности.
В противном случае, если это состояние с сохранением состояния, это явный случай совместного владения, поскольку DoStuffWithRef действительно нужно продлить время жизни отдельного живого экземпляра LargeObject до самого себя. Или используйте слабый указатель и съешьте стоимость проверки во время выполнения …