Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning constructor-less object as output parameter

Tags:

c++

I want to return an object from a function as an output parameter, but the object has no default constructor so I can't do this:

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))
    {
        ...
    }
}

So, it looks like I should return it on the heap and manage it with a shared_ptr instance, like this:

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);

        ...
    }
}

The downside is that anyone calling the method will have to remember that he is responsible for deallocating the object.
What is the best practice for returning constructor-less objects as output parameters?

like image 349
drifter Avatar asked Jun 27 '26 00:06

drifter


2 Answers

Return by value is almost always the best solution if the object supports copy (and objects which will be declared on the stack should generally support copy). If the function can fail, and not always return an object, you can use some sort of Fallible or Maybe class:

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 );
}

You might reflect, though: if GetSomeObjectList() can always return a reference to an existing list (rather than constructing a list internally), and you modify it to return a const reference, you could just return a pointer:

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;
}

This is a very typical C++ idiom.

like image 121
James Kanze Avatar answered Jun 29 '26 12:06

James Kanze


Instead of returning a bool and passing in a reference have the function return a smart pointer, ensuring the caller cannot forget to deallocate:

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);
}
like image 28
hmjd Avatar answered Jun 29 '26 14:06

hmjd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!