unique_ptr
не будет работать из-за getDevice()
, верно?
Нет, не обязательно. Здесь важно определить соответствующую политику владения для вашего Device
объекта, то есть того, кто будет владельцем объекта, на который указывает ваш (умный) указатель.
Это будет экземпляр объекта Settings
отдельно? Будет ли объект Device
уничтожаться автоматически, когда объект Settings
будет уничтожен, или он должен пережить этот объект?
В первом случае std::unique_ptr
- это то, что вам нужно, поскольку оно делает Settings
единственным (уникальным) владельцем указанного объекта и единственным объектом, который несет ответственность за его уничтожение.
В этом предположении getDevice()
должен возвращать простой указатель наблюдения (указатели наблюдения - это указатели, которые не поддерживают активность указанного объекта). Самый простой вид указателя наблюдения - это необработанный указатель:
#include <memory>
class Device {
};
class Settings {
std::unique_ptr<Device> device;
public:
Settings(std::unique_ptr<Device> d) {
device = std::move(d);
}
Device* getDevice() {
return device.get();
}
};
int main() {
std::unique_ptr<Device> device(new Device());
Settings settings(std::move(device));
// ...
Device *myDevice = settings.getDevice();
// do something with myDevice...
}
[ПРИМЕЧАНИЕ 1: Вам может быть интересно, почему я использую здесь необработанные указатели, когда все продолжают говорить, что необработанные указатели - это плохо, небезопасно и опасно. На самом деле это ценное предупреждение, но важно изложить его в правильном контексте: необработанные указатели плохи, когда используются для ручного управления памятью, то есть для выделения и освобождения объектов с помощью new
и delete
. При использовании исключительно как средство достижения ссылочной семантики и передачи не принадлежащих, наблюдающих указателей, в необработанных указателях нет ничего опасного по сути, за исключением, может быть, того факта, что не следует разыменовать висячий указатель. - КОНЕЦ ПРИМЕЧАНИЕ 1]
[ПРИМЕЧАНИЕ 2: Как выяснилось в комментариях, в этом конкретном случае, когда право собственности уникально, и принадлежащий объект всегда гарантированно присутствует (т. е. внутренний член данных device
никогда не будет nullptr
), функция getDevice()
может (а может и должна) возвращать ссылку, а не указатель. Хотя это правда, я решил вернуть здесь необработанный указатель, потому что имел в виду, что это будет короткий ответ, который можно обобщить на случай, когда device
может быть nullptr
, и чтобы показать, что исходные указатели в порядке, если не использовать их для ручного управления памятью. - КОНЕЦ ПРИМЕЧАНИЕ 2]
Ситуация, конечно, кардинально иная, если ваш Settings
объект не должен обладать исключительным правом собственности на устройство. Это может иметь место, например, если разрушение объекта Settings
не должно означать уничтожение указанного объекта Device
.
Это то, что можете сказать только вы как разработчик своей программы; из приведенного вами примера мне трудно сказать, так это или нет.
Чтобы помочь вам в этом разобраться, вы можете спросить себя, есть ли какие-либо другие объекты, кроме Settings
, которые имеют право поддерживать объект Device
в живых, пока они содержат указатель на него, вместо того, чтобы быть просто пассивными наблюдателями. Если это действительно так, вам понадобится политика совместного владения, что предлагает std::shared_ptr
:
#include <memory>
class Device {
};
class Settings {
std::shared_ptr<Device> device;
public:
Settings(std::shared_ptr<Device> const& d) {
device = d;
}
std::shared_ptr<Device> getDevice() {
return device;
}
};
int main() {
std::shared_ptr<Device> device = std::make_shared<Device>();
Settings settings(device);
// ...
std::shared_ptr<Device> myDevice = settings.getDevice();
// do something with myDevice...
}
Обратите внимание, что weak_ptr
является наблюдающим указателем, а не указателем-владельцем - другими словами, он не поддерживает указанный объект в живых, если все другие указатели-владельцы на указанный объект выходят за пределы области видимости.
Преимущество weak_ptr
перед обычным необработанным указателем состоит в том, что вы можете безопасно определить, является ли weak_ptr
висячим или нет (то есть указывает ли он на действительный объект или объект, на который изначально указывался, был уничтожен) . Это можно сделать, вызвав функцию-член expired()
для объекта weak_ptr
.
person
Andy Prowl
schedule
26.03.2013
device
конструкторуsettings
, хотите ли вы по-прежнему иметь возможность ссылаться на него в вызывающей области или только черезsettings
? Если последнее,unique_ptr
полезно. Кроме того, у вас есть сценарий, в котором возвращаемое значениеgetDevice()
равноnull
. Если нет, просто верните ссылку. - person Keith   schedule 27.03.2013shared_ptr
правильно в 8/10 случаях. Остальные 2/10 делятся междуunique_ptr
иweak_ptr
. Кроме того,weak_ptr
обычно используется для разрыва циклических ссылок; Я не уверен, что ваше использование будет считаться правильным. - person Collin Dauphinee   schedule 27.03.2013device
? Сначала вы должны это решить. - person juanchopanza   schedule 27.03.2013unique_ptr
и передать право собственности при вызове конструктора, если я знаю, что он мне больше не понадобится. Но как разработчик классаSettings
я не знаю, хочет ли вызывающий также сохранить ссылку. Возможно, устройство будет использоваться во многих местах. Хорошо, может быть, это именно твоя точка зрения. В этом случае я бы не был единственным владельцем, и, думаю, тогда я бы использовал shared_ptr. И: значит, умные точки заменяют указатели, но не ссылки, верно? - person michaelk   schedule 27.03.2013unique_ptr
переменной-членом, вероятно, главным из них является неявное удаление стандартного конструктора копирования. Это удаление, возможно, делает использование вашего класса крайне неинтуитивным для любого программиста, работающего ниже по течению. См. https://stackoverflow.com/questions/16030081/copy-constructor-for-a-class-with-unique-ptr - person ldog   schedule 18.04.2020