Выбрасывание неконстантных временных файлов по ссылке

Есть ли проблема с выбросом объекта, созданного в стеке в блоке try, по неконстантной ссылке, его перехватом и изменением, а затем выбросом по ссылке на другой блок catch?

Ниже приводится краткий пример того, о чем я говорю.

struct EC {
    EC(string msg) { what = msg; }
    string where;
    string what;

    void app(string& t) { where += t; }
    string get() { return what; }
};

try {
    try {
        try {
            EC error("Test");
            throw error;
        }
        catch (EC& e) {
            e.app("1");
            throw e;
        }
    }
    catch (EC& e) {
        e.app("2");
        throw e;
    }
}
catch (EC& e) {
     e.app("3");
     cout << e.where << endl;
     cout << e.get() << endl;
}

Возможно ли, что это может привести к тому, что е. Что будет содержать мусор, а е. Место останется нетронутым? Например:
e.where is "123"
e.get () возвращает много мусорных данных, пока не попадет в нулевой байт.


person Collin Dauphinee    schedule 16.02.2010    source источник
comment
Не могу воспроизвести. Также не будет компилироваться с неконстантной ссылкой в ​​app (). В любом случае вы не кидаете ссылку, вы кидаете копию.   -  person UncleBens    schedule 16.02.2010
comment
Это не предназначено для компиляции. Код просто иллюстрирует то, о чем я говорю. Я спросил, может ли что-то подобное привести к тому, что e.get () будет содержать ненужные данные, а не если он компилируется и работает.   -  person Collin Dauphinee    schedule 16.02.2010
comment
Учитывая, что это не настоящий код, вполне вероятно, что e.get () вернет мусор, если требуется конструктор копирования.   -  person Hans Passant    schedule 16.02.2010


Ответы (1)


Не существует такого понятия, как «выброс по ссылке». Это просто невозможно. Для этого нет синтаксиса. Каждый раз, когда вы пытаетесь «выбросить ссылку», фактически создается копия указанного объекта. Излишне говорить, что в вашем коде нет попыток кидать по ссылке.

Можно перехватить ранее созданное исключение по ссылке (даже неконстантной) и изменить через нее временный объект исключения. Это будет работать. Фактически, вы можете повторно генерировать измененный теперь существующий объект исключения вместо создания нового объекта. Т.е. ты можешь просто сделать

throw;

вместо

throw e;

в ваших предложениях catch и по-прежнему получите правильно работающий код, то есть исходный объект (с модификациями) продолжит свой полет через иерархию обработчиков.

Однако ваш код неправильно сформирован на

e.app("1"); 

вызов (и другие вызовы app), поскольку параметр не является ссылкой на константу. Измените объявление app на

void app(const string& t) { where += t; }  // <- either this
void app(string t) { where += t; }         // <- or this

для его компиляции.

В противном случае ваш код должен работать нормально. Вы не должны получать мусор от get(). Если вы это сделаете, это должно быть проблема с вашим компилятором или с вашим кодом, который вы не показываете.

person AnT    schedule 16.02.2010
comment
вероятно, стоит упомянуть, что вы должны поймать по ссылке, чтобы избежать нарезки объекта - person jk.; 16.02.2010
comment
что произойдет, если у меня будет MyClass obj, а затем throw &obj? Это подкидывание ссылки? - person Cătălina Sîrbu; 28.03.2020
comment
@ CătălinaSîrbu Нет. Почему вы вообще упоминаете ссылки в этом контексте? - person AnT; 30.03.2020