C++11 のクラス メンバーとしてのスマート ポインターの使用法が理解できません。スマート ポインターについてはたくさん読んでおり、一般的な仕組みは理解していると思いますunique_ptr
。shared_ptr
理解weak_ptr
できないのは実際の使用法です。ほとんどの場合、誰もが を使用することを推奨しているようですunique_ptr
。しかし、次のようなものをどのように実装すればよいのでしょうか。
class Device {
};
class Settings {
Device *device;
public:
Settings(Device *device) {
this->device = device;
}
Device *getDevice() {
return device;
}
};
int main() {
Device *device = new Device();
Settings settings(device);
// ...
Device *myDevice = settings.getDevice();
// do something with myDevice...
}
ポインターをスマート ポインターに置き換えたいとします。unique_ptr
は のgetDevice()
せいで機能しませんよね? その場合は と を使用しますshared_ptr
。weak_ptr
を使用する方法はありません。非常に小さなスコープでポインターを使用しているのでない限り、ほとんどの場合 の方が理にかなっているようにunique_ptr
思えます。shared_ptr
class Device {
};
class Settings {
std::shared_ptr<Device> device;
public:
Settings(std::shared_ptr<Device> device) {
this->device = device;
}
std::weak_ptr<Device> getDevice() {
return device;
}
};
int main() {
std::shared_ptr<Device> device(new Device());
Settings settings(device);
// ...
std::weak_ptr<Device> myDevice = settings.getDevice();
// do something with myDevice...
}
それが正しいやり方ですか?どうもありがとうございます!
ベストアンサー1
A は
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
。