Обнаруживать или избегать мертвых ссылок на временные во время компиляции

Следующие ошибки в программе минимальной длины при компиляции с -O3 и, возможно, с -O2, но хорошо работает с -O0 (с лязгом 4.0):

#include <iostream>

class A {
public:
virtual void me() const { std::cerr << "hi!\n"; }
};

class B {
public:
B(const A& a_) : a(a_) {}
virtual void me() const { a.me(); }

private:
const A& a;
};

class C {
public:
C(const B& b_) : b(b_) {}
void me() const { b.me(); }

public:
const B& b;
};

int main() {
C c = C(A());
c.me();
}

Причина в том, что c.b инициализируется со ссылкой на временный объект класса B который построен из временного A, После конструктора c.C() выходы временные B нет, но ссылка на него остается в c.b,

Какие хорошие практики я могу использовать, чтобы избежать этой ситуации, учитывая, что я не контролирую реализацию B или же A? Существуют ли статические анализаторы, способные обнаружить это состояние? (Моя версия scan-build не нашел проблемы.)

Связанные с: Обнаружить висячие ссылки на временные

0

Решение

Мне лично не нравится иметь переменные-члены в качестве ссылок. Они не могут быть скопированы или перемещены, и пользователь класса должен убедиться, что объект переживает саму ссылку. Исключением может быть внутренний вспомогательный класс, предназначенный для использования в качестве только временных объектов, таких как функторы.

Замена ссылки указателем должна быть простой, а затем, если вы также используете указатель в конструкторе:

class C {
public:
C(const A *a_) : a(a_) {}
private:
const A *a;
};

…и так далее. Если класс очень большой, и вы чувствуете себя ленивым и не хотите менять члена, вы можете просто изменить конструктор:

class C {
public:
C(const A *a_) : a(*a_) {}
private:
const A &a;
};

Чтобы неправильно использовать этот класс, как говорит ОП, вам нужно написать что-то вроде:

C c = C(&A());

И тогда ошибка должна быть очевидна: указатель на временный указатель — очень плохая идея!

PS: я бы добавил explicit для вашего конструктора, просто чтобы он не участвовал в автоматических преобразованиях, которые, я думаю, являются частью вашей проблемы.

1

Другие решения

Я бы получил отдельные классы от B а также C (возможно, даже используя шаблонный класс).

Эти классы будут содержать нереферентный член, который становится a а также b Ссылаться на.

Затем я бы реализовал необходимые конструкторы копирования / операторы присваивания в этих производных классах, чтобы предотвратить висячие ссылки.

(Тогда у меня был бы крепкий разговор с автором B а также C).

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector