0

問題:2つのコンストラクターを持つコピー不可能なオブジェクトがあります。コンストラクターの1つを使用してオブジェクトを作成し、それをいくつかの一般的なコード内で使用する必要があります。-

コピー可能なオブジェクトを使用すると、次のようになり、簡単になります。

Object a;

if (condition) 
   a = Object(p1);
else
   a = Object(p2,p3,p4);

a.doSomething();

しかし、オブジェクトはコピーできないので、私はこれをしなければなりませんでした:

boost::scoped_ptr<Object> a;

if (condition) 
   a = new Object(p1);
else
   a = new Object(p2,p3,p4);

a->doSomething();

これは複雑すぎると感じます。より良い解決策はありますか?

4

7 に答える 7

4

これは非常にひどいハックObjectです。デフォルトで構築可能であると仮定します。

Object a;
a.~Object();

if (condition) { ::new (&a) Object(p1); }
else           { ::new (&a) Object(p2, p3, p4); }

これは使用しないでください。

別のオプションはユニオンを使用することですが、そのセットアップでもデストラクタを手動で呼び出す必要があります。


Boost.Optionalインプレースファクトリを使用)を使用すると、よりクリーンなソリューションを実現できます。(詳細を掘り下げてくれた@ K-Balloに感謝します!)

#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>

struct Object
{
    explicit Object(int) {}
    explicit Object(int, float, std::string) {}

    Object(Object const &)             = delete;
    Object(Object &&)                  = delete;
    Object & operator=(Object const &) = delete;
    Object & operator=(Object &&)      = delete;
};

boost::optional<Object> a;

if (condition) { a = boost::in_place(0); }
else           { a = boost::in_place(0, 1.0f, "two" ); }
于 2013-01-18T18:09:40.427 に答える
3

私にはそれがそうであるように完全に合理的に見えます。それは明確で、単純で、比較的簡潔です。

于 2013-01-18T18:10:41.417 に答える
1

複雑さはわかりません...ポインタを宣言し、newを使用するif条件に基づいて効率的に構築する必要がある場合は、唯一のオプションです。必ずしも行う必要はありません。

  1. scoped_ptrを使用します(通常はそれが良い考えですが)
  2. 「メイン」コードのifにコンストラクターを含めます。あなたはファクトリの典型的なユースケースです(例えばhttp://en.wikipedia.org/wiki/Factory_method_patternを参照)。

編集:2番目の文に「効率的に」追加されました。

于 2013-01-18T18:16:20.813 に答える
1
auto const doSomethingTo = []( Object&& o ) { o.doSomething(); };
doSomethingTo( condition? Object( p1 ) : Object( p1, p2, p3 ) );

免責事項:コンパイラが触れていないコード。


編集:上記のコードは、Object( Object&& )コンストラクターがprivateの場合、MSVC 11.0ではコンパイルできませんが(昨年の11月のCTPでも可能です)、MinGW g++4.7.1および一部のバージョンのclangでは正常にコンパイルされます。

コンパイルする必要があるようです。

したがって、これはおそらくVisual C ++のバグですが、残念ながら、簡単な回避策は見つかりませんでした。


想定されるVisualC++コンパイラのバグに対する不安な回避策

#include <fstream>
#include <iostream>
using namespace std;

class Object
{
private:
    Object( Object const& );
    Object( Object&& );
public:
    void doSomething() const {}
    Object( int ) {}
    Object( int, int, int ) {}
};

int main( int argc, char* argv[] )
{
    int p1 = 0, p2 = 0, p3 = 0;
    bool condition = argc == 2;

    auto const doSomething1 = [=]() { Object o( p1 ); o.doSomething(); };
    auto const doSomething2 = [=]() { Object o( p1, p2, p3 ); o.doSomething(); };

    if( condition ) { doSomething1(); } else { doSomething2(); }
}

new別の答えは、 (動的割り当てを読む)が唯一の選択肢であると主張しています。

それは間違っている。

于 2013-01-18T19:57:23.127 に答える
1

他の人がすでに述べたように、あなたの解決策には本当に何も悪いことはありませんが、条件演算子を使用した方が、そうである場合よりも読みやすくなります。ただし、リファクタリングの可能性を考慮する必要があります。オブジェクトを使用するすべてのコードを別の関数に分解すると(参照によってオブジェクトを取得する)、次のようになります。

if ( condition ) {
    Object a( p1 );
    doWhatever( a );
} else {
    Object a( p2, p3, p4 );
    doWhatever( a );
}

望ましいかもしれません(またはそうではありません。これら2つのどちらを選択するかに関して「正しい」答えはないと思います)。

于 2013-01-19T01:33:49.603 に答える
0

あなたのコードは大丈夫だと思います。

条件演算子を検討したいだけかもしれません ? :

boost::scoped_ptr<Object> a( condition ? new Object(p1) : new Object(p2,p3,p4) );
a->doSomething();
于 2013-01-18T18:18:25.427 に答える
0

したがって、オブジェクトを手動で作成せずに、これを機能させるための簡単なトリックを次に示します。代わりに、Deferred<T>構築が延期される(そしておそらく発生しない)自動ストレージ内のオブジェクトを表すテンプレートを作成しました。

buffinは、アライメントの問題を処理するためDeferred、に置き換える必要がありunionます(これをサポートするC ++ 11機能があると仮定します)。constructedあなたが電話をするときに真実であると主張することget()はおそらく良い考えです。

オブジェクトを作成したら、暗黙的にをにキャストDeferred<T>T&、それをT&deferred-constructedのエイリアスとして使用できますT

理論的には、constructed boolそれが常に構築されることを証明できれば、それを廃止することができますが、私はそれに反対することをお勧めします。それ以外は、これはあなたがそれをやってのけることができるのとほぼ同じくらい効率的であるはずです。また、C ++ 11のunion場合は、標準に準拠している可能性もあります。

そうそう、それは完璧な転送で強化されるべきです。

#include <utility>

// does not handle alignment issues:
template<typename T>
struct Deferred {
   Deferred():constructed(false) {}
  operator T&() { return get(); }
  T& get() { return *reinterpret_cast<T*>(&buff[0]); }
  template<typename... Args>
  T& construct( Args... args ) {
    new(&buff[0]) T(args...);
    constructed = true;
    return get();
  }
  ~Deferred() {
    if (constructed) {
      get().~T();
    }
  }
private:
  bool constructed;
  char buff[sizeof(T)];
};

#include <iostream>

struct Object {
  bool is_int;
  Object( int x ):is_int(true) {}
  Object( double d ):is_int(false) {}
  ~Object() {
    std::cout << "~Object("<<is_int<<") destroyed\n";
  }
};

enum which_test {
  as_int,
  as_double,
  do_not,
};
void test(which_test v) {
  std::cout << v << "\n";
  Deferred<Object> o;
  if(v==as_int) {
    o.construct( 7 );
  } else if (v==as_double) {
    o.construct( 7.0 );
  } else {
  }
}

int main() {
  test(as_int);
  test(as_double);
  test(do_not);
}
于 2013-01-21T16:14:03.453 に答える