1

I am trying to convert between two classes and avoid a temporary object.

Here is my declaration for Square:

class CSquare
{
public:
    int dimension;
    CSquare(int dimension);

    // Conversion to Rectangle
    operator CRectangle();

    ~CSquare(void);
};

and here is my declaration for Rectangle:

class CRectangle
{
public:
    int length;
    int width;

    CRectangle(int length, int width);

    //Copy Constructor
    CRectangle(const CRectangle& anotherRectangle); 

    ~CRectangle(void);
};

Why does

CSquare aSquare = CSquare(10);
    CRectangle convertedRect = (CRectangle) aSquare;

invoke the copy constructor?

I have a conversion function:

CSquare::operator CRectangle(){
    return CRectangle(CSquare::dimension,CSquare::dimension);
}

but I'm still getting a temporary object.

How do I avoid the temporary object?

1
  • I forgot to praise you for not having Rectangle deriving from Square or the other way around :) Commented Feb 1, 2011 at 18:46

8 Answers 8

5

You can avoid copy construction by writing a conversion constructor in CRectangle:

CRectangle::CRectangle(const CSquare & sq)
    :length(sq.dimension),
     width(sq.dimension)
{}
...
...
CSquare aSquare(10);
CRectangle convertedRect(aSquare);
Sign up to request clarification or add additional context in comments.

3 Comments

And yet another, better way would be to not define Rectangle and Square differently. Squareness is a predicate that operates on rectangles. If a rectangle has all sides equal then it is square.
@Noah: Yes, you could define a function for Rectangle to test that, but that doesn't imply that you should not define a Square class, if one is warranted.
while we are it, perhaps that recommending explicit in front of CRectangle would make sense :) ?
2

Because you're copying a Rectangle.

I honestly don't know what else to say. Compilers are free to optimize away the call in the case you're showing, but they don't have to. Apparently yours is not.

Edit....

As to how to avoid it, you really can't. You could try to crank up the optimizations but it can be extremely difficult to see if you've succeeded, especially with such a small, trivial construct. If I where you I wouldn't be so worried about it unless I really found, by profiling my code, that an inordinate amount of time was being spent in that function. Then I'd be looking for ways to crunch the algorithms using the code to reduce copies.

1 Comment

I am not sure whether Visual C++ was optimizing in Debug Mode actually.
1

How do I avoid the temporary object?

You don't. That's how conversions work. The temporary may be elided (constructing directly into the destination), but that is not required.

It sounds like you want move semantics, which are in C++0x. Even then, the temporary "exists", but it can be moved instead of copied, which, for types where it matters, is often much more efficient.

Is this square/rectangle case not really the situation you care about and only used here for an example?

Comments

0

I would assume since operator CRectangle returns an instance of CRectangle, the copy constructor is invoked for the return value.

2 Comments

No. The constructor is invoked when they use initialization syntax to create a copy of that return in a local object.
@NoahRoberts: That is true, but the copy ctor may also be used for the return value. In fact, temporaries in this case can be copied many times, or none with RVO.
0

In general this depends on the compiler. Return value optimization is done by most compiler. So instead of creating a temporary object and assign it to your object the copy Ctor from your object is called.

Also take a look here Copy constructor vs. return value optimization

Comments

0

A temporary CRectangle object is being created, then copied to convertedRect.

2 Comments

Not possible in standard C++.
@UncleBens - what? What is not possible?
0

I can't tell which type of object you're saying has a temporary.

If the square, then you need to remove any excuse for the compiler to create one:

CSquare aSquare(10);

If the rectangle, then you shoudl use a converting constructor instead of an operator, as suggested by @PigBen:

Rectangle::CRectangle(const CSquare & sq)
    :length(sq.dimension),
     width(sq.dimension)
{}
// And then:
CRectangle convertedRect(aSquare);

Comments

0

In this particular case, you do it by not having the conversion function and instead use inheritance. E.g.:

class CRectangle
{
public:
    int length;
    int width;

    CRectangle(int length, int width);
};

class CSquare : public CRectangle
{
public:
    CSquare(int dimension) : length(dimension), width(dimension)
    {}
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.