简体   繁体   English

VS2010中的条件运算符正确行为?

[英]Conditional operator correct behaviour in VS2010?

I'm wondering whether this bit of code is exhibiting the correct C++ behaviour? 我想知道这段代码是否表现出正确的C ++行为?

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: 在VS2008中内置时,输出为:

fooA name: alan
fooA name: foofoo

But when the same code is built in VS2010 it becomes: 但是当在VS2010中构建相同的代码时,它变为:

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 . 正在“alan”上调用复制构造函数,尽管通过引用传递(或者不是视情况而定),但fooA被调用的ChangeName保持不变。

Has the C++ standard changed, has Microsoft fixed incorrect behaviour or have they introduced a bug? C ++标准是否已更改,Microsoft是否修正了不正确的行为或是否引入了错误?

Incidentally, why is the copy constructor being called ? 顺便说一句, 为什么要调用复制构造函数

A fuller answer: 更全面的答案:

5.16/4&5: 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. “4如果第二个和第三个操作数是左值并且具有相同的类型,则结果属于该类型并且是左值。

5 Otherwise the result is an rvalue...." 5否则结果是右值......“

In other words, "bool ? lvalue:rvalue" results in a temporary. 换句话说,“bool?lvalue:rvalue”会导致暂时的。

That would be the end of it, however you pass this into a function that, according to C++, MUST receive an lvalue as parameter. 这将是它的结束,但是你将它传递给一个函数,根据C ++,它必须接收一个左值作为参数。 Since you pass it an rvalue you actually have code that is not C++. 因为你传递了一个rvalue,你实际上拥有的代码不是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. MSVC ++接受它,因为它是愚蠢的,并使用一堆它没有告诉你的扩展,除非你把它变成一个挂件。 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. 既然你所拥有的不是标准的C ++,并且MS只是通过扩展允许它,那么关于它的“正确”再也没有什么可说的了。

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). 在条件表达式中,第二个操作数是Foo类型的左值 ,而第三个是Foo类型的右值 (函数的返回值不返回引用)。

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. 这意味着条件的结果是rvalue而不是左值 (无论第一个表达式的值是什么),然后您无法将其绑定到非const引用。 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? 据我所知,这是由5.16第3点的C ++标准所涵盖的,不是吗?

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.]" 它说“如果E2是一个右值,或者如果上面的转换不能完成:如果E1和E2有类型,并且底层类型相同或者一个是另一个的基类:E1可以转换为匹配E2如果T2的类型与T1类的基类相同,或者T2的cv资格与cv资格相同,或者cv资格等于cv资格。 T1。如果应用转换,E1将更改为T2类型的右值,该值仍然引用原始源类对象(或其相应的子对象)。[注意:即,不进行复制。]“

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." 奇怪的是,参考评论“Yep。将警告级别转为4并再次编译”。 (Noah Roberts), apparently there is a warning provided that 'ChangeName' takes a non-const reference. (Noah Roberts),显然有一个警告,提供'ChangeName'采用非const引用。 If this is a function that takes a const-reference then there's no warning, but the temporary variable is still created. 如果这是一个采用const-reference的函数,那么就没有警告,但仍然创建了临时变量。 Perhaps this is just another vaguary of the Microsoft compiler. 也许这只是微软编译器的另一个流行病。

编译器显然正在评估:。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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