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

如果对象支持复制(并且将在堆栈上声明的对象通常应该支持复制),则按值返回几乎总是最好的解决方案。如果函数可能失败,并且并不总是返回一个对象,您可以使用某种FallibleMaybe类:

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 参数,而是返回一个值。由于该值是可选的,如当前返回类型 bool 所示,您可以将boost::optional其用于该目的:

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 回答