*** ВНИМАНИЕ: Блог переехал на другой адрес - demin.ws ***

воскресенье, 8 августа 2010 г.

Странные скобки в С++

Недавно более часа потратил на поиск проблемы в куске кода, упрощенный вариант которого привожу ниже:

#include <iostream>
int x;
struct A {
  A(int a) {
    x = a;
  }
};
struct B {
  B(A a) {
    A local_a = a;
  }
};
int main() {
  x = 0;
  std::cout << "Case #0: " << x << std::endl;
  B b1(A(1));
  std::cout << "Case #1: " << x << std::endl;
  int t;
  t = 2;
  B b2(A(t));
  std::cout << "Case #2: " << x << std::endl;
  t = 3;
  B b3((A(t)));
  std::cout << "Case #3: " << x << std::endl;
  return 0;
}

Как вы думаете, что должна вывести эта программа? Числа 0, 1, 2 и 3 последовательно для каждого случая?

А она печатает:

Case #0: 0
Case #1: 1
Case #2: 1
Case #3: 3

Почему для случая #2 не произошло присваивание? Куда делась двойка?

Ответ на этот вопрос кроется в наличии рудиментов языка С в грамматике С++.

9 комментариев:

  1. Вы ведь уже писали про это...
    http://easy-coding.blogspot.com/2009/02/c.html

    ОтветитьУдалить
  2. Писал, точно. Но это было давно, а баг свежий, и тема весьма запутанная. И может кто-то не читал тот пост.

    ОтветитьУдалить
  3. Имхо, объяснение по ссылке очень сложное для такого примера. Здесь получается просто, что выражение
    B b2(A(t));
    интерпретируется как
    B b2(A t);
    т.е. получается локальная переменная с конструктором без параметров, потому что игнорируются скобочки вокруг (t).
    А баг, конечно, бредовый. С++ не устаёт нас "радовать".

    ОтветитьУдалить
  4. выражение
    B b2(A(t));
    интерпретируется как
    B b2(A t);

    у A нет конструктора по умолчанию

    ОтветитьУдалить
  5. Fanruten, действительно, я и забыл, что явно заданный конструктор убивает неявного...

    Но я был неправ только частично. Оно действительно интерпретируется как
    B b2(A t);
    Вот только это не есть создание локальной переменной и вызов конструктора, а означает определение функции b2, с параметром A и возвращающей B. Всё равно проще, чем объяснение по ссылке :)

    ОтветитьУдалить
  6. > Всё равно проще, чем объяснение по ссылке :)
    Неа :) Объяснение по ссылке просто более полно описывает ситуацию.

    ОтветитьУдалить
  7. Тоже интересно.
    Что будет напечатано?


    #include
    #include

    struct Foo
    {
    const int m_value;
    static std::vector ms_vector;
    Foo()
    :
    m_value(ms_vector.size())
    {
    std::cout << m_value << std::endl;
    }
    };


    Foo f1;

    std::vector Foo::ms_vector(5);

    Foo f2;

    int main()
    {
    return 0;
    }

    ОтветитьУдалить
  8. Что-то подобное спрашивают мега-гуру на собеседованиях )))

    ОтветитьУдалить