14

コピー不可能なオブジェクトを扱うベストプラクティスを探しています。

明らかにコピーできないミューテックスクラスがあります。それを強制するために、プライベートコピーコンストラクターを追加しました。

それはコードを壊しました-いくつかの場所は単に修正する必要がありましたが、データメンバーとして、または継承によってミューテックスを使用するクラスがコンテナーに挿入されているという一般的な問題があります。

これは通常、コンテナーの初期化中に発生するため、ミューテックスはまだ初期化されていないため問題ありませんが、コピー コンストラクターがないと機能しません。ポインターを含むようにコンテナーを変更することはできません。

何かアドバイスはありますか?

4

10 に答える 10

11

ここでの 3 つのソリューション:

1. ポインターを使用する- 簡単な解決策は、ポインターのコンテナーにすることshared_ptrです。

オブジェクトが真にコピー不可能であり、他のコンテナを使用できない場合、これは「良い」解決策です。

2. その他のコンテナー - または、非コピー コンテナー (インプレース構築を使用する) を使用することもできますが、それらはあまり一般的ではなく、STL との互換性がほとんどありません。(ちょっとやってみたけどダメだった)

オブジェクトが真にコピー不可能であり、ポインターを使用できない場合、それは「神」の解決策になります。

[編集] C++13 では、std::vector はインプレース構築 (emplace_back) を許可し、移動セマンティクスを実装するコピー不可能なオブジェクトに使用できます。[/編集]

3. コピー可能性を修正する- クラスがそのままコピー可能であり、mutex がそうでない場合、コピー コンストラクターと代入演算子を「単純に」修正する必要があります。

通常、ミューテックスを除くすべてのメンバーをコピーして割り当てる必要があるため、それらを記述するのは面倒ですが、多くの場合、次の方法で簡略化できます。

template <typename TNonCopyable>
struct NeverCopy : public T 
{
    NeverCopy() {}
    NeverCopy(T const & rhs) {}

    NeverCopy<T> & operator=(T const & rhs) { return *this; }
}

そして、ミューテックスメンバーを

NeverCopy<Mutex> m_mutex;

残念ながら、そのテンプレートを使用すると、Mutex の特別なコンストラクターが失われます。

[編集] 警告:コピー CTor/代入を「修正」するには、多くの場合、コピー コンストラクトで右側をロックし、代入で両側をロックする必要があります。残念ながら、copy ctor/assignment をオーバーライドしてデフォルトの実装を呼び出す方法はありません。そのため、このトリックNeverCopyは外部ロックなしでは機能しない可能性があります。(独自の制限がある他のいくつかの回避策があります。)

于 2010-08-11T10:59:51.227 に答える
4

それらがコピー不可能な場合、コンテナーはそれらのオブジェクトへの (スマートな) ポインターを格納するか、ラッパーなどを参照する必要がありますが、C++0x では、コピー不可能なオブジェクトは引き続き (ブースト スレッドのように) 移動できるため、そのまま容器に収納。

例を挙げます: 参照ラッパー (boost::ref とも呼ばれ、フードの下のポインター)

#include <vector>
#include <tr1/functional>
struct Noncopy {
private:
        Noncopy(const Noncopy&) {}
public:
        Noncopy() {}
};
int main()
{
        std::vector<std::tr1::reference_wrapper<Noncopy> > v;
        Noncopy m;
        v.push_back(std::tr1::reference_wrapper<Noncopy>(m));
}

C++0x、gcc でテスト:

#include <vector>
struct Movable {
private:
        Movable(const Movable&) = delete;
public:
        Movable() {}
        Movable(Movable&&) {}
};
int main()
{
        std::vector<Movable> v;
        Movable m;
        v.emplace_back(std::move(m));
}

編集: 気にしないでください、C++0x FCD は、30.4.1/3 の下で、

Mutex 型は、コピー可能でも移動可能でもありません。

したがって、それらへのポインターを使用したほうがよいでしょう。必要に応じてスマートまたはラップされます。

于 2010-08-11T10:50:51.503 に答える
3

オブジェクトがコピー不可の場合、通常は正当な理由があります。そして、正当な理由がある場合は、それをコピーしようとするコンテナーに入れて、それを覆すべきではありません。

于 2010-08-11T10:47:33.240 に答える
2

あなたがそれをどのように組み立てたかを考えると、質問に対する本当の答えはありません。あなたが望むことをする方法はありません。実際の答えは、コンテナーにポインターを含めることであり、特定されていない理由でそれは問題ないと言いました。

あるものは移動可能であり、C++0x を使用することについて話している人もいます。この場合、コンテナはしばしば要素を移動可能にする必要がありますが、コピー可能にする必要はありません。ミューテックスが保持されている間はミューテックスを移動すべきではないと思われるため、これも不十分な解決策であると思います。これにより、ミューテックスを移動することが事実上不可能になります。

したがって、実際に残っている唯一の答えは、ミューテックスを指すことです。::std::tr1::shared_ptr( 内の#include <tr1/memory>) またはを使用::boost::shared_ptrして、ミューテックスをポイントします。これには、ミューテックスを内部に持つクラスの定義を変更する必要がありますが、とにかくそうしているように聞こえます。

于 2010-08-11T11:46:19.080 に答える
1

boost::shared_ptr などのスマート ポインターを使用するか、boost::intrusive などの別のコンテナーを使用します。どちらも、コードを変更する必要があります。

于 2010-08-11T11:44:00.590 に答える
1

STL コンテナーは、コンテンツがコピー可能であることに大きく依存しているため、コピー可能にするか、コンテナーに入れないでください。

于 2010-08-11T10:49:05.903 に答える
1

最適なオプションは、ポインターを使用するか、内部でポインターを使用するある種のラッパー クラスを使用することです。これにより、これらを正常にコピーでき、実際にコピーに期待されることを実行できます (ミューテックスを共有します)。

しかし、あなたはポインタを言わなかったので、もう1つのオプションがあります. ミューテックスは「時々コピー可能」であるように思えます。おそらく、コピー コンストラクターと代入演算子を作成し、初期化後にミューテックスがコピーされた場合に例外をスローする必要があります。欠点は、実行時まで間違っていることを知る方法がないことです。

于 2010-08-11T10:51:17.287 に答える
0

クラスでミューテックスを使用しても、必ずしもそのクラスがコピー不可でなければならないというわけではありません。次のように(ほとんど)いつでも実装できます。

C::C (C const & c)
// No ctor-initializer here.
{
  MutexLock guard (c.mutex);

  // Do the copy-construction here.
  x = c.x;
}

これにより、ミューテックスを使用してクラスをコピーすることがいくらか可能になりますが、おそらく行うべきではありません。インスタンスごとのミューテックスを使用しない方が、設計が改善される可能性があります。

于 2010-08-11T11:14:05.570 に答える