cinnamon
cinnamon

Reputation: 1760

RVO when converting return value

I struggle with the complexity of conversions and casting, and I can't find advice online that clearly guarantees efficient conversion on function return. I have two classes, Base and Derived, where Derived has no extra data members over Base. I have a named constructor for the base class that I want to return using RVO and cast to an object of the derived type with as little overhead as possible.

class Base { 
public:
    static Base namedConstructor(int n){
        return Base(n);
    } 
protected:
    Base(int n) : member(n){
    }
    int member; 
};

class Derived : public Base  {
    static Derived nC2(int n) {
        Derived derived = namedConstructor(n); 
        // Error: no suitable user-defined conversion from "Base" to "Derived"... 
        // modify derived
        return derived; 
    } 
};

Is there a way to fix the error that satisfies all the following requirements?

  1. No use of RTTI. Dynamic casting seems unnecessary.
  2. Only one definition of namedConstructor in case I need to modify it. If necessary, I can make it a template, but I am interested in the alternatives.
  3. namedConstructor should take advantage of RVO in nC2.
  4. The conversion should not silently fail if I add or remove data members from either the base or the derived class (something similar to reinterpret_cast may do this).

Upvotes: 0

Views: 187

Answers (2)

Manuel
Manuel

Reputation: 2554

I've added constructors and with g++ 3.0 there is copy elision:

class Base { 
public:
    static Base namedConstructor(int n){
        return Base(n);
    } 
protected:
    Base(int n) : member(n){
        std::cout << "Create Base" << std::endl;
    }
    Base (const Base & b) : member (b.member) {
        std::cout << "Copy Base" << std::endl;
    }
    int member; 
};

class Derived : public Base  {
public:
    Derived () : Base (0) {
        std::cout << "Create Derived" << std::endl;
    }
    Derived (const Base & b) : Base(b) {
        std::cout << "Create Derived from base" << std::endl;
    }
    int val () { return member; }
    static Derived nC2(int n) {
        return namedConstructor(n); //derived; 
    } 
};

int main ()
{
    Derived d = Derived::nC2(1);
    std::cout << "Value: " << d.val() << std::endl;
    return 0;
}

The output from this is:

Create Base
Copy Base
Create Derived from base
Value: 1

so one Base creation, one copy of Base when creating Derived and the Derived itself.

There are no copies from namedConstructor exit or nC2, nor for the assignment in main.

I've compiled this with -O0 but with those so small functions may be there is optimization here and those are removed.

Upvotes: 1

Dr. Gut
Dr. Gut

Reputation: 2836

Add a private ctor. to Derived, which constructs it from a Base:

Derived(const Base& base) : Base(base) {
}

If later you add extra member variables to Derived, initialize them also.

This is standard-compliant (although a little bit weird), and will be optimized away in release builds.

Upvotes: 1

Related Questions