web-dev-qa-db-ja.com

スタックオブジェクトへのshared_ptrの作成

私のメソッドでは、Playerオブジェクトは次のように作成されます。

Player player(fullName,age);

私の先生は、shared_ptrをプレーヤーオブジェクトに取得するコンストラクターを使用してコードを提供してくれました。

//constructor of the class
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player)

SomeClassのコンストラクターを呼び出して、作成したプレーヤーオブジェクトをスタックに渡したいとしましょう。

スタックオブジェクトからshared_ptrを作成することは安全/可能/良いですか?

質問をより理解しやすくするために、2つの大きなコードプロジェクトがあり、それらをマージして、あるプロジェクトのメソッドが別のプロジェクトから呼び出されるようにするとします。すべてのファイルを書き換えて、shared_ptrを使用するか、オブジェクトを排他的にスタックします(接続する必要があります)、またはスタックオブジェクトにshared_ptrを作成する必要があります。

なぜ結果がわからないのですか:

Stackobjectが作成されたスコープが終了しても、shared_ptrが引き続き使用されている場合、またはその逆の場合はどうなりますか。

スコープ外の場合、stackobjectは削除されますか、それともオブジェクトへの参照がまだあるため(別のクラスにあります)、存続しますか?

Shared_ptrはスコープ外になり、オブジェクトを削除しようとしますが、stackobjectがそれを参照していても、削除できますか?

注:以下を使用してプレーヤーを渡すことができることはわかっています

shared_ptr<Player> player{ new Player {fullName,age} };
11

スタックオブジェクトからsmart_ptrを作成することは安全/可能/良いですか?

安全?そのオブジェクトを作成したスタックが、それを疑似所有するすべてのshared_ptrの後でのみ終了することを保証できる場合にのみ。

可能?確かに:shared_ptrのコンストラクターに何もしない削除オブジェクトを渡します:

auto sptr = shared_ptr<Player>(&player, [](Player *) {});

最後のshared_ptrが破棄されると、削除者が呼び出され、何も削除されません。

良い?あんまり。上記のように、安全性はそのようなコードで普遍的に保証できるものではありません。コード構造によっては、これが正当な場合があります。しかし、それは細心の注意が必要です。

このSomeClassは、リソースの所有権を主張することを期待しています。そのため、shared_ptrを使用しています。参照するオブジェクトを実際には所有していないshared_ptrを渡すことで、嘘をついているようなものです。つまり、オブジェクトの存続期間を共有制御するというSomeClassに対する約束に違反しないようにする責任は、あなたとあなたのコード構造にあります。

22
Nicol Bolas

共有ポインタの目的は、動的に作成されたオブジェクトの存続期間を管理することです。オブジェクトを指す共有ポインタがある限り、そのオブジェクトはまだ存在している必要があります。オブジェクトを指す最後の共有ポインタが破棄されると、そのオブジェクトは破棄されます。

スタックオブジェクトの有効期間は根本的に異なります。コードが作成されたスコープから出るまで存在し、その後破棄されます。

ライフタイムの2つの概念には互換性がありません。共有ポインターが、スコープ外になったスタックオブジェクトがまだ存在していることを保証する方法はありません。

したがって、2つを混合しないでください。

4
Pete Becker

スタックオブジェクトからshared_ptrを作成することは安全/可能/良いですか?

安全ではないという@NicolasBolasに同意します。しかし、スタックオブジェクトのcopyからshared_ptrを作成するのは安全かもしれません

shared_ptr<Player> playerPtr(new Player(player));

もちろん、Playerがコピー可能であれば。

2
Semmel

スタックオブジェクトは、含まれている関数が返されるとすぐに破棄されるため、スタックオブジェクトへの共有ポインタを作成するのは安全ではありません。ローカルオブジェクトは暗黙的かつ自動的に割り当ておよび割り当て解除され、介入しようとすると、確かに多くの種類の未定義の動作が呼び出されます。

2
alter igel

安全は強い言葉です。ただし、StackObjectSharedPtrを定義し、shared_ptrインスタンス化型に「特別な」StackObjectDeleterを含めるように強制することで、コードをより安全にすることができます。

using PlayerStackSP = std::shared_ptr <Player, StackObjectDeleter> ;

class StackObjectDeleter {
public:
    void operator () (void*) const {}
};

Player player(fullName,age);
std::shared_ptr<PlayerStackSP, StackObjectDeleter> player(&player, StackObjectDeleter());

StackObjectDeleterは、deleterオブジェクトとしてdefault_deleteを置き換えます。 default_deleteは、単にdelete(またはdelete [])を呼び出します。 StackObjectDeleterの場合、何も起こりません。

これは@NicolBolasの答えの一歩です。

1
Daniel Heilper

移動セマンティクスを使用してshared_ptrを作成します

std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };

このようにして、コピーが回避されます。このアプローチを機能させるには、関連するクラスにmoveコンストラクターを実装する必要がある場合があります。ほとんど/すべてのstdオブジェクトは、箱から出して移動セマンティクスをサポートします(例:stringvectorなど)

0
darune