简体   繁体   中英

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 ?

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.

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.

As far as I can tell, this is covered by the C++ standard in 5.16 point 3, isn't it?

It says "if E2 is an rvalue, or if the conversion above cannot be done: if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to an rvalue of type T2 that still refers to the original source class object (or the appropriate subobject thereof). [Note: that is, no copy is made.]"

Doesn't this describe the situation above? I thought that it did, but am willing to accept that I may be wrong if someone could explain why it doesn't.

Thanks.

Oddly, with reference to the comment "Yep. Turn warning level to 4 and compile again." (Noah Roberts), apparently there is a warning provided that 'ChangeName' takes a non-const reference. If this is a function that takes a const-reference then there's no warning, but the temporary variable is still created. Perhaps this is just another vaguary of the Microsoft compiler.

编译器显然正在评估:。

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