简体   繁体   中英

Is it good practice to give an empty instance to a method?

C++ newbie here! There is a class Individual which allocates a lot of memories so that we want to avoid having to copy. Let mother and father be two Individual s. I would like them to reproduce with the method reproduce to make another Individual called baby .

Intuitively, I would initialize baby with the default constructor, pass it in argument to reproduce and return the reference (although I suppose it is not necessary to return the reference). Here is a code that does that

class Individual
{
    public:
        void reproduce (const Individual& father, Individual& baby)
        {
          // Set all attributes of baby
        }
    private:
        // Plenty of variables
}

int main()
{
  // Do Stuff
    Individual mother(arg1,arg2,arg3);
    Individual father(arg1,arg2,arg3);
    // Do stuff
    Individual baby;
    mother.reproduce(father,baby);
}

Is this considered good practice?

Another way would be to initialize baby directly in the method reproduce and return a reference but I would predict that the baby would be destroyed at the end of the call of reproduce though.

class Individual
{
    public:
        Individual& reproduce (const Individual& father)
        {
            Individual baby;
        // Set all attributes of baby
        return baby
        }
    private:
        // Plenty of variables
}

int main()
{
  // Do Stuff
    Individual mother(arg1,arg2,arg3);
    Individual father(arg1,arg2,arg3);
    // Do stuff
    auto baby = mother.reproduce(father);
}

One could as well use an external function but I don't see what advantage that could represent.

The member function reproduce should return the baby.

It makes no sense to have a baby beforehand that's merely altered by the act of reproduction — this would be more akin to your parents finding the baby on the doorstep, having been deposited by a stork, then moulding the baby into their family; hopefully you know by now that this is not how it works!

Don't worry about performance; if your Individual class has a move constructor (or follows the rule of zero) then this is a complete non-issue. Even if not, Return Value Optimisation should take care of things anyway.

Your attempt to return a reference to a local variable has undefined behaviour, as you correctly intuited. So don't do this.

I would give the Individual class a constructor that takes two Individual input parameters, eg:

class Individual
{
public:
    Individual(Individual const& mother, Individual const& father)
    {
        // Pass on traits.
    }
};

Unless, of course, reproduction also modifies the parents with relaxation, shame, or a sexually transmitted disease.

You are correct about following:

Another way would be to initialize baby directly in the method reproduce and return a reference but I would predict that the baby would be destroyed at the end of the call of reproduce though.

So the first way is definetely better than abovementioned.

However, I would prefer (and this is just my IMHO) using the dynamic allocation. You can use your first method in case if you are absolutely sure, that reproduce method is not failable, and it would not be failable in future (that thing no one knows for sure).

Just imagine how your code will look like?

Individual baby;
mother.reproduce(father,baby);
if (baby.exists()) {
   // do stuff
}

The problem here that you are creating the baby even not being sure it would be created. I would prefer following, wherer you can be sure the (if you write the right code) that all the allocations will be done only if required.

Individual* reproduce (Individual *father)
...
Individual *baby = mother->reproduce(father);
if (baby != nullptr) {
    // do stuff
}

or

bool reproduce (Individual *father, Individual * &baby) // or **baby
...
Individual *baby = nullptr;
if (mother->reproduce(father, baby) {
    // do stuff
}

The second way is bit more error-prone or complex (as you should take care of baby passed is not existing, otherwise overwriting it could lead to memory leaks). Note: I prefer uniform code (and objects usage) so changed the mother and father to pointers, which is not the "must done" thing.

Also, this way you can even safely store the pointers babies in some internal "children" list in mother without copying data.

PS Just remember to delete the baby when it's not more needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM