Условный оператор правильного поведения в VS2010? - PullRequest
3 голосов
/ 16 сентября 2010

Мне интересно, демонстрирует ли этот бит кода правильное поведение 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;
}

При сборке в VS2008 вывод:

fooA name: alan
fooA name: foofoo

Но когда тот же кодвстроен в VS2010 и становится:

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

Конструктор копирования вызывается на «alan», и, несмотря на то, что он передается по ссылке (или нет, в зависимости от обстоятельств), fooA не изменяется вызываемымChangeName.

Изменился ли стандарт C ++, исправило ли Microsoft некорректное поведение или ввели ошибку?

Кстати, почему конструктор копированиябудучи названным ?

Ответы [ 5 ]

5 голосов
/ 16 сентября 2010

Более полный ответ:

5.16 / 4 & 5:

"4 Если второй и третий операнды являются lvalue и имеют одинаковый тип, результат этого типа и lvalue.

5 В противном случае результатом является rvalue .... "

Другими словами," bool? Lvalue: rvalue "приводит к временному.

Это будет конецоднако вы передаете это в функцию, которая, согласно C ++, ДОЛЖНА получить lvalue в качестве параметра.Поскольку вы передаете его как r-значение, у вас фактически есть код, который не является C ++.MSVC ++ принимает его, потому что это глупо и использует кучу расширений, о которых он вам не скажет, если вы не превратите его в подвеску.Поскольку то, что у вас есть, не является стандартным C ++ для начала, и MS просто позволяет это расширять, на самом деле ничего нельзя сказать о том, что является «правильным» в этом отношении.

3 голосов
/ 16 сентября 2010

В вашем условном выражении ваш второй операнд является lvalue типа Foo, а третий - rvalue типа Foo (возвращаемое значение функции невозвращение ссылки).

Это означает, что результатом условного выражения является rvalue , а не lvalue (независимо от значения первого выражения), которое вы можетезатем привязать к неконстантной ссылке.Поскольку вы нарушили это правило, вы не можете вызвать языковой стандарт, чтобы указать, каким должно быть правильное поведение любой версии компилятора.

Результатом условного выражения будет lvalue , если обавторой и третий операнды имеют одинаковый тип lvalue .

Edit: Технически, обе версии нарушают стандарт, поскольку ни одна из них не выдает диагностическое сообщение, когда вы нарушилидиагностируемое правило стандарта.

0 голосов
/ 16 сентября 2010

Как ни странно, со ссылкой на комментарий «Да. Поверните уровень предупреждения на 4 и снова скомпилируйте».(Ноа Робертс), очевидно, есть предупреждение при условии, что «ChangeName» принимает неконстантную ссылку.Если это функция, которая принимает константную ссылку, то предупреждения нет, но временная переменная все еще создается.Возможно, это просто очередная путаница компилятора Microsoft.

0 голосов
/ 16 сентября 2010

Насколько я могу судить, это охватывается стандартом C ++ в 5.16, пункт 3, не так ли?

В нем говорится "если E2 является r-значением, или если приведенное выше преобразование не может быть сделано: если E1 и E2 имеют тип класса, и базовые типы классов одинаковы или один является базовым классом другого: E1 может быть преобразован для соответствия E2, если класс T2 того же типа, что и базовый класскласс T1 и cv-квалификация T2 - это та же cv-квалификация, что и cv-квалификация, или более высокая, чем cv-квалификация T1. Если преобразование применяется, E1 заменяется на r-значение типа T2это все еще относится к исходному объекту исходного класса (или соответствующему подобъекту). [Примечание: то есть, копия не создается.] "

Разве это не описывает ситуацию выше?Я думал, что это так, но я готов признать, что могу ошибаться, если кто-то сможет объяснить, почему это не так.

Спасибо.

0 голосов
/ 16 сентября 2010

Компилятор явно оценивает обе стороны:.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...