Брошенный объект копирует конструкции - почему? - PullRequest
1 голос
/ 22 марта 2011

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

#include <iostream>
#include <exception>

using namespace std;

struct my_exception : std::exception { 
  my_exception() { 
    cout << "my_exception(): this=" << hex << (unsigned long)this << endl;
  }

  my_exception( my_exception const& ) { 
    cout << "my_exception( my_exception const& )" << endl;
  }

  ~my_exception() throw() { 
    cout << "~my_exception()" << endl;
  }

  my_exception& tweak() { 
    return *this;
  }

  char const* what() const throw() { return "my_exception"; }
};

int main() {
  try {
    throw my_exception().tweak();
  }
  catch ( my_exception const &e ) { 
    cout << "&e=" << hex << (unsigned long)&e << endl;
  }
}

Когда я запускаю программу, я получаю:

my_exception(): this=7fff5fbfeae0
my_exception( my_exception const& )
~my_exception()
&e=1001000f0
~my_exception()

Как видите, пойманный объект исключения - это не тот, который изначально был брошен. Если я уберу вызов tweak(), я получу:

my_exception(): this=1001000f0
&e=1001000f0
~my_exception()

Для случая, когда вызывается tweak(), почему вызывается конструктор копирования? Я хочу, чтобы tweak() работал с первоначально сконструированным объектом, и никакая копия не будет сделана. Есть ли способ предотвратить создание копии?

К вашему сведению: я использую g ++ 4.2.1 (часть Xcode в Mac OS X).

Ответы [ 3 ]

5 голосов
/ 22 марта 2011

Исключение выдается по значению. Вы не можете бросить ссылку в качестве ссылки. При попытке копирования объект копируется (используя статически известный тип).

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

РЕДАКТИРОВАТЬ (см. Комментарии): например, это неопределенное поведение для распространения исключения через обратный вызов C. Но если вы определили подходящий класс исключений, вы можете его клонировать, а в C ++ снова запустить цепочку вызовов с помощью виртуального метода.

Приветствия и hth.,

3 голосов
/ 22 марта 2011

Чтобы добавить к ответу Альфа, тот факт, что вы не получаете операцию копирования, когда не вызываете tweak(), заключается в том, что стандарт разрешает (но не требует) исключения вызовов конструктору копирования для созданияобъект временного исключения.Из C ++ 03 15.1 / 5 (Бросив исключение):

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

Если вы сделаете конструктор копирования закрытым, gcc выдаст вам ошибку (даже если конструктор общедоступен, он не вызывается).MSVC не выдаст ошибку, но я должен подумать.

0 голосов
/ 22 марта 2011

AFAIK следующее происходит в вашей строке throw my_exception().tweak();:

создается новый объект my_exception (локально, в стеке), tweak () возвращает ссылку на этот локальный объект.Затем, когда вы выбрасываете эту ссылку, вы выходите из области видимости и локальный объект удаляется.Таким образом, реализация копирует класс в динамическую память, чтобы сохранить действительную ссылку.

Во втором случае вы бросаете его по значению, и он сразу выделяется в динамической памяти.

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