Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional operator correct behaviour in VS2010?

I'm wondering whether this bit of code is exhibiting the correct C++ behaviour?

class Foo
{
public:
    Foo(std::string name) : m_name(name) {}

    Foo(const Foo& other) { 
        std::cout << "in copy constructor:" << other.GetName() << std::endl;
        m_name = other.GetName();
    }

    std::string GetName() const { return m_name; }
    void SetName(std::string name) { m_name = name; }

private:
    std::string m_name;
};

Foo CreateFoo(std::string name)
{
    Foo result(name);
    return result;
}

void ChangeName(Foo& foo)
{
    foo.SetName("foofoo");
}

int _tmain(int argc, _TCHAR* argv[])
{
    Foo fooA("alan");
    std::cout << "fooA name: " << fooA.GetName() << std::endl;
    bool b = true;
    ChangeName(b ? fooA : CreateFoo("fooB"));
    std::cout << "fooA name: " << fooA.GetName() << std::endl;
    return 0;
}

When built in VS2008 the output is:

fooA name: alan
fooA name: foofoo

But when the same code is built in VS2010 it becomes:

fooA name: alan
in copy constructor: alan
fooA name: alan

A copy constructor is being invoked on 'alan' and, despite being passed by reference (or not as the case may be), fooA is unchanged by the called to ChangeName.

Has the C++ standard changed, has Microsoft fixed incorrect behaviour or have they introduced a bug?

Incidentally, why is the copy constructor being called?

like image 293
WalderFrey Avatar asked Apr 19 '26 02:04

WalderFrey


2 Answers

A fuller answer:

5.16/4&5:

"4 If the second and third operands are lvalues and have the same type the result is of that type and is an lvalue.

5 Otherwise the result is an rvalue...."

In other words, "bool ? lvalue:rvalue" results in a temporary.

That would be the end of it, however you pass this into a function that, according to C++, MUST receive an lvalue as parameter. Since you pass it an rvalue you actually have code that is not C++. MSVC++ accepts it because it's stupid and uses a bunch of extensions it doesn't tell you about unless you turn it into a pendant. Since what you have is not standard C++ to begin with, and MS is just allowing it by extension, nothing can really be said about what is "correct" regarding it anymore.

like image 55
Edward Strange Avatar answered Apr 21 '26 16:04

Edward Strange


In your conditional expression, your second operand is an lvalue of type Foo, while the third is an rvalue of type Foo (return value of a function not returning a reference).

This means that the result of the conditional is an rvalue not an lvalue (whatever the value of the first expression), which you can't then bind to a non-const reference. As you've violated this rule you can't invoke the language standard to state what the correct behaviour of either compiler version should be.

The result of a conditional is an lvalue if both second and third operands are lvalues of the same type.

Edit: Technically, both versions are in violation of the standard as neither issued a diagnostic when you violated a diagnosable rule of the standard.

like image 28
CB Bailey Avatar answered Apr 21 '26 18:04

CB Bailey



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!