Время жизни неявно брошенных временных - PullRequest
1 голос
/ 24 декабря 2010

Я видел этот вопрос . Кажется, что вне зависимости от приведения временный объект (ы) будет «выживать» до тех пор, пока не будет оценена полная экспрессия. Но по следующему сценарию:

template<class T>
struct bar {
    T t;
    bar(T t) : t(t) {}
    template<class U>
    bar(bar<U> other) : t(other.t) {}
};
void foo(bar<const double&> b) {
    printf("%lf\n", b.t);
}
int main() {
    foo(bar<const double&>(2));//#1
    foo(bar<int>(2));          //#2
    return 0;
}

1 работает хорошо, а 2 - нет. И MSVC дал мне предупреждение о 2: «Ссылочный элемент инициализируется как временный, который не сохраняется после выхода из конструктора»

Теперь мне интересно, почему они оба создают временный double объект и передают его bar<const double&>, и только 2 не удалось.

@ обновление

Я использую struct bar вместо boost::tuple в исходном посте, надеюсь, он станет более знакомым для других.

Позвольте мне прояснить мой вопрос. В # 1 из int (2) создается временное double, а затем из него создается bar<const double &> и копируется в foo, в то время как в # 2 создается временное bar<int> и временное double создается из члена bar<int> в ctor bar<const double&>. Кажется, что временное double разрушено в foo в # 2, а не в # 1. Зачем? Я думаю, что все они являются частью фуллэкспрессии и будут существовать до bar возвращения.

Тим говорит: "Компилятор достаточно умен, чтобы рассматривать эти 2 как двойные вместо целых." поэтому я написал int i = 2; и передал i обоим вызовам, но все идет как прежде. Я сделал это в VS2008 с режимом отладки.

Ответы [ 4 ]

1 голос
/ 25 декабря 2010

. # 1 звонки boost::tuple<const double&>::tuple(const double&).Для этого временным double создается полное выражение foo(boost::tuple<const double&>(2)).Затем создается временный boost::tuple<const double&>.У него есть ссылочный элемент, который связан с временным double.Оба временных значения существуют до тех пор, пока не выполнено полное выражение # 1, и остаются действительными, когда вызывается foo.

. # 2 вызывает boost::tuple<const double&>::tuple(const boost::tuple<int>&).Это выражение создает временный boost::tuple<int>.Срок службы этого временного аналога не является проблемой.Но подумайте, что происходит, когда вызывается этот конструктор tuple.Упрощенные / псевдокодовые классы:

template<> class tuple<int> {
  private:
    int member1_;
  //...
};

template<> class tuple<const double&> {
  private:
    const double& member1_;
  public:
    tuple(const tuple<int>& int_tup) : member1_(int_tup.member1_) {}
  // ...
};

mem-initializer member1(int_tup.member1_) преобразует значение int во временный double и связывает это double со ссылкой на класс.Этот временный double создается полным выражением member1_(int_tup.member1_), а не полным выражением foo(boost::make_tuple(2)).Специальное исключение для mem-initializer гарантирует, что временный double будет в порядке до конца конструктора, в котором он был создан, но тогда нет гарантии, что он все еще действителен при вызове foo.

Такважное отличие состоит в том, что оператор # 1 сам создает временный double, но оператор № 2 косвенно вызывает создание временного double в другой функции.Точно , который полное выражение создает временное, влияет на то, как долго будет жить этот временный.

1 голос
/ 25 декабря 2010

В # 2, временное tuple<double const&> построено из tuple<int> в качестве аргумента n для foo. Перед построением tuple<double const&> временный двойник (D) построен из члена int tuple<int> и double const& элемент инициализируется как D. Временные объекты, созданные для подготовки аргументов функции, разрушаются когда вызов функции завершен. Таким образом, D уничтожается, когда заканчивается конструктор tuple<double const&>.

Надеюсь, это поможет

0 голосов
/ 24 декабря 2010

Предисловие: я не эксперт по Boost или Tuple.Я никогда не использовал ни того, ни другого.В любом случае я постараюсь быть полезным.

Мне кажется, что boost::make_tuple(2) возвращает tuple<int>.Однако, по-видимому, выполняется неявное приведение, соответствующее вашей реализации foo, в течение которого он может пытаться использовать адрес временного (преобразование int в const double&) ненадлежащим образом.

Вы пытались явно разыграть своего make_tuple?

Опять же, я не эксперт по бусту или кортежу, но я бы попробовал:

 foo(boost::make_tuple(boost::cref((double)2)));//#2

или

 foo(boost::make_tuple((const double&)2);//#2

Я признаю, что здесь я делаю обоснованное предположение, пытаясь помочь, поэтому я не обещаю, что это правильное дерево, чтобы лаять.

0 голосов
/ 24 декабря 2010

Я считаю, что строка # 1 в порядке, потому что ссылки на const могут ссылаться на временные.Кто-то может, вероятно, процитировать стандарт на это.

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