クラスメンバーにスマートポインタを使用する 質問する

クラスメンバーにスマートポインタを使用する 質問する

C++11 のクラス メンバーとしてのスマート ポインターの使用法が理解できません。スマート ポインターについてはたくさん読んでおり、一般的な仕組みは理解していると思いますunique_ptrshared_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_ptrweak_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

おすすめ記事