A unique_ptr
не работает из-за getDevice()
, правильно?
Нет, не обязательно. Здесь важно определить подходящую политику собственности для вашего объекта Device
, то есть кто будет владельцем объекта, на который указывает ваш (умный) указатель.
Это будет случай объекта Settings
? Будет ли объект Device
уничтожен автоматически, когда объект Settings
будет уничтожен или он должен пережить этот объект?
В первом случае std::unique_ptr
- это то, что вам нужно, так как он является единственным (уникальным) владельцем заостренного объекта и единственным объектом, который несет ответственность за его уничтожение.
В этом предположении 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
, и показать, что необработанные указатели в порядке, если не использовать их для ручного управления памятью. - END Примечание 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
.
Это помогает быть предельно ясным в отношении срока службы, владения и возможных нулей. Например, передав 'device' конструктору' settings', вы хотите все еще иметь возможность ссылаться на него в области вызова или только через 'settings'? Если последнее, 'unique_ptr' полезно. Кроме того, есть ли сценарий, в котором возвращаемое значение 'getDevice()' равно 'null'. Если нет, просто верните ссылку. – Keith
Да, 'shared_ptr' верен в 8/10 случаях. Остальные 2/10 разделяются между 'unique_ptr' и' weak_ptr'. Кроме того, 'weak_ptr' обычно используется для разрыва круговых ссылок; Я не уверен, что ваше использование будет считаться правильным. –
Прежде всего, какое владение вы хотите для члена данных 'device'? Вы сначала должны это решить. – juanchopanza