Информация об изменениях

Сообщение ссылка на базовый класс без вирт деструктора от 22.08.2023 15:18

Изменено 22.08.2023 17:07 Sm0ke

ссылка на базовый класс без вирт деструктора
До недавнего времени я считал, что если временный объект класса Наследник
привязать к ссылке на константный класс База
то чтобы конечный объект разрушился правильно необходимо в базе задать виртуальный деструктор.

Но оказывается даже если в базе нет никакого явного деструктора, то деструктор наследника всё равно вызовется в этом случае.

Вот тест: https://godbolt.org/z/qncnsce79

В нём за базу взята структура t_param
А за наследника t_error : t_param

#include <iostream>
#include <string_view>

using t_text = std::string_view;
using namespace std::literals::string_view_literals;

struct t_param
{
  // data
  t_text
    status;
};

struct t_error : public t_param
{
  t_error(t_text p) : t_param{p} {}
  ~t_error() { std::cout << "~t_error: " << this->status << '\n'; }
};

void go1(const t_param & p) { std::cout << "go1()\n"; }
void go2(t_param && p) { std::cout << "go2()\n"; }

int main()
{
  const t_param & cv = t_error{"const t_param & cv"sv};
  t_param && rv = t_error{"t_param && rv"sv};
  go1(t_error{"go1(const t_param & p)"sv});
  go2(t_error{"go2(t_param && p)"sv});
  try
  {
    std::cout << "going to throw\n";
    throw t_error{"throw"sv};
  } catch( const t_param & e ) {
    std::cout << "catch\n";
  }
  std::cout << "end\n";
  return 0;
}


Вот output:

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
go1()
~t_error: go1(const t_param & p)
go2()
~t_error: go2(t_param && p)
going to throw
catch
~t_error: throw
end
~t_error: t_param && rv
~t_error: const t_param & cv


Тобишь и по правой сслыке на базу, и по левой константной, — всё равно деструктор наследника отрабатывает.
И как параметр функции, и как throw База catch Наследник.

Это по стандарту? Или компиляторы импровизируют?
Кстати проверено на: clang, gcc, msvc

Если по стандарту, то зачем тогда спрашивается в std::exception деструктор сделан виртуальным?
Может есть какие use кейсы, где это необходимо?
ссылка на базовый класс без вирт деструктора
До недавнего времени я считал, что если временный объект класса Наследник
привязать к ссылке на константный класс База
то чтобы конечный объект разрушился правильно необходимо в базе задать виртуальный деструктор.

Но оказывается даже если в базе нет никакого явного деструктора, то деструктор наследника всё равно вызовется в этом случае.

Вот тест: https://godbolt.org/z/qncnsce79

В нём за базу взята структура t_param
А за наследника t_error : t_param

#include <iostream>
#include <string_view>

using t_text = std::string_view;
using namespace std::literals::string_view_literals;

struct t_param
{
  // data
  t_text
    status;
};

struct t_error : public t_param
{
  t_error(t_text p) : t_param{p} {}
  ~t_error() { std::cout << "~t_error: " << this->status << '\n'; }
};

void go1(const t_param & p) { std::cout << "go1()\n"; }
void go2(t_param && p) { std::cout << "go2()\n"; }

int main()
{
  const t_param & cv = t_error{"const t_param & cv"sv};
  t_param && rv = t_error{"t_param && rv"sv};
  go1(t_error{"go1(const t_param & p)"sv});
  go2(t_error{"go2(t_param && p)"sv});
  try
  {
    std::cout << "going to throw\n";
    throw t_error{"throw"sv};
  } catch( const t_param & e ) {
    std::cout << "catch\n";
  }
  std::cout << "end\n";
  return 0;
}


Вот output:

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
go1()
~t_error: go1(const t_param & p)
go2()
~t_error: go2(t_param && p)
going to throw
catch
~t_error: throw
end
~t_error: t_param && rv
~t_error: const t_param & cv


Тобишь и по правой сслыке на базу, и по левой константной, — всё равно деструктор наследника отрабатывает.
И как параметр функции, и как throw Наследник catch База.

Это по стандарту? Или компиляторы импровизируют?
Кстати проверено на: clang, gcc, msvc

Если по стандарту, то зачем тогда спрашивается в std::exception деструктор сделан виртуальным?
Может есть какие use кейсы, где это необходимо?