Является ли прямое создание ссылки на rvalue определенным поведением? - PullRequest
0 голосов
/ 09 февраля 2019

Следующий код компилируется корректно, используя g ++ 6.3.0 с -Wall.

#include <iostream>

class Base
{
public:
    Base(char const* base) : base_(base) {}
    void print( char const* msg ) { print( base_, msg ); }

protected:
    ~Base() = default;

private:
    char const* base_;
    virtual void print( char const*, char const* ) = 0;
};

class Drv1 : public Base
{
public:
    Drv1(char const* base, int i) : Base(base) , i_(i) {}
    ~Drv1() { std::cout << "Drv1 dtor" << std::endl; }

private:
    int     i_;

    void print( char const* base, char const* msg ) override
    {
        std::cout << base << "(" << msg << "): " << i_ << std::endl;
    }
};

class Drv2 : public Base
{
public:
    Drv2(char const* base, double d) : Base(base) , d_(d) {}
    ~Drv2() { std::cout << "Drv2 dtor" << std::endl; }

private:
    double     d_;

    void print( char const* base, char const* msg ) override
    {
        std::cout << base << "(" << msg << "): " << d_ << std::endl;
    }
};


void do_test( char const* base, char const* msg, bool int_type )
{
    Base&&   _base(int_type ? (Base&&)Drv1(base, 1) : (Base&&)Drv2(base, 2.5));

    _base.print( msg );
}

int main()
{
    do_test( "Test1", "int", true );
    do_test( "Test2", "double", false );
    return 0;
} 

Вывод при запуске следующий:

Drv1 dtor
Test1(int): 1
Drv2 dtor
Test2(double): 2.5

Вопросы:

  1. Как это может быть определено поведение, если деструкторы производного класса были вызваны до вызова виртуальных функций?Если выходные данные на самом деле просто случайность, каковы параметры компилятора для решения этой проблемы?

  2. Является ли rvalue reference правильной терминологией для типа локальной переменной _base вdo_test()?Универсальные (или пересылаемые) ссылки встречаются в контексте шаблонов, но здесь нет шаблонов.

1 Ответ

0 голосов
/ 09 февраля 2019

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

Программа имеет UB.В этом выражении: (Base&&)Drv2(base, 2.5) создается временный объект, и к нему привязывается ссылка.Затем ссылка используется для инициализации другой ссылки в полном выражении Base&& _base(int_type ? (Base&&)Drv1(base, 1) : (Base&&)Drv2(base, 2.5));.Время жизни временного объекта, на которое ссылается временная ссылка, не увеличивается на время жизни _base.Таким образом, ссылка остается висячей.Более поздний доступ к значению имеет неопределенное поведение.

Продление времени жизни временного объекта работает только при прямой инициализации ссылки с помощью выражения, которое создает временный объект.Например:

Base&&   _base(Drv2(base, 2.5));
...