2

関数からオブジェクトを出力パラメーターとして返したいのですが、オブジェクトにはデフォルトのコンストラクターがないため、これを行うことはできません。

bool FindFlaggedObject(MyObject& myObject)
{
    std::vector<MyObject> myObjects = GetSomeObjectList();
    for (UINT i = 0; i < myObjects.size(); i++)
    {
        if (myObjects[i].Flag) {
            myObject = myObjects[i];
            return true;
        }
    }
    return false;
}

void main()
{
    MyObject myObject;  // NOT ALLOWED - OBJECT HAS NO DEFAULT CONSTRUCTOR
    if (FindFlaggedObject(myObject))
    {
        ...
    }
}

したがって、ヒープに戻し、shared_ptrインスタンスで次のように管理する必要があるようです。

bool FindFlaggedObject(MyObject& myObject)
{
    std::vector<MyObject> myObjects = GetSomeObjectList();
    for (UINT i = 0; i < myObjects.size(); i++)
    {
        if (myObjects[i].Flag) {
            myObject = new MyObject(myObjects[i]);
            return true;
        }
    }
    return false;
}

void main()
{
    MyObject* myObjectPtr;
    if (FindFlaggedObject(myObjectPtr))
    {
        std::shared_ptr<MyObject> myObject(myObjectPtr);

        ...
    }
}

欠点は、メソッドを呼び出す人は誰でも、オブジェクトの割り当てを解除する責任があることを覚えておく必要があることです。
コンストラクターのないオブジェクトを出力パラメーターとして返すためのベストプラクティスは何ですか?

4

4 に答える 4

5

オブジェクトがコピーをサポートしている場合は、ほとんどの場合、値による戻りが最適なソリューションです (スタック上で宣言されるオブジェクトは通常、コピーをサポートする必要があります)。関数が失敗する可能性があり、常にオブジェクトを返すとは限らない場合は、ある種のFallibleまたはMaybeクラスを使用できます。

Fallible<MyObject>
FindFlaggedObject()
{
    std::vector<MyObject> objects = GetSomeObjectList();
    std::vector<MyObject>::const_iterator current = objects.begin();
    while ( current != objects.end() && !current->flag ) {
        ++ current;
    }
    return current == objects.end()
        ? Fallible<MyObject>()
        : Fallible<MyObject>( *current );
}

GetSomeObjectList() が (内部的にリストを構築するのではなく) 常に既存のリストへの参照を返すことができ、それを変更して const 参照を返す場合は、単にポインターを返すことができます。

MyObject const*
FindFlaggedObject()
{
    std::vector<MyObject> const& objects = GetSomeObjectList();
    std::vector<MyObject>::const_iterator current = objects.begin();
    while ( current != objects.end() && !current->flag ) {
        ++ current;
    }
    return current == objects.end()
        ? NULL
        : &*current;
}

これは非常に典型的な C++ イディオムです。

于 2012-04-16T15:01:05.807 に答える
3

を返して参照を渡す代わりにbool、関数がスマート ポインターを返すようにして、呼び出し元が割り当て解除を忘れないようにします。

std::shared_ptr<MyObject> myObjectPtr = FindFlaggedObject();
if (myObjectPtr)
{
    // Found flagged object.
}

std::shared_ptr<MyObject> FindFlaggedObject()
{
    MyObject* result = nullptr;
    std::vector<MyObject> myObjects = GetSomeObjectList();
    for (UINT i = 0; i < myObjects.size(); i++)
    {
        if (myObjects[i].Flag) {
            result = new MyObject(myObjects[i]);
            break;
        }
    }
    return std::shared_ptr<MyObject>(result);
}
于 2012-04-16T15:00:09.647 に答える
2

out パラメータを使用する代わりに、値を返します。boost::optionalbool の現在の戻り値の型で示されるように、値はオプションであるため、その目的で使用できます。

boost::optional<MyObject> FindFlaggedObject()
{
    std::vector<MyObject> myObjects = GetSomeObjectList();
    for (UINT i = 0; i < myObjects.size(); i++)
    {
        if (myObjects[i].Flag) {
            return myObjects[i];
        }
    }
    return boost::none;
}
于 2012-04-16T15:00:16.443 に答える
0

デフォルトのコンストラクターを使用して自動オブジェクトを作成する必要はありません。コンストラクターパラメーターを渡すだけです。

void main()
{
   MyObject myObject (12); 
   if (FindFlaggedObject(myObject))
   {
     ...
   }
}

反対に、なぜこのようにしないのですか?

MyObject FindFlaggedObject()
{
 std::vector<MyObject> myObjects = GetSomeObjectList();
 for (UINT i = 0; i < myObjects.size(); i++)
 {
     if (myObjects[i].Flag) {
         return myObjects[i];
     }
 }
 return 0;
}

void main()
{
   MyObject* res = FindFlaggedObject();
   if (res != 0) {
      ...
   }
}

resがGetSomeObjectListのメンバーである限り、resを削除する必要はありません。

于 2012-04-16T14:54:50.157 に答える