Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / throw class / 19 сообщений из 19, страница 1 из 1
25.05.2013, 01:01
    #38272952
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Следующий код:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
#include <stdio.h>

class a {
public:
  int f;
  a(int v) { f = v; };
  a(a& o) { f = o.f+1; o.f=0; printf("a copy invoked\n"); };
  ~a() { printf("a destructed\n"); };
};

class b: public a {
public:
  int k;
  b(int v): a(v) { k = v-1; };
  ~b() { printf("b destructed\n"); };
};

int main()
{
  b x(2);
  printf("x.f = %d\nx.k = %d\n", x.f, x.k);
  try
  {
  try
   {
    throw b(3);
   }
   catch (const b& ex)
   {
     printf("ex.f = %d\nex.k = %d\n", ex.f, ex.k);
     throw;
   }
  }
  catch (const b& ex)
  {
    printf("ex2.f = %d\nex2.k = %d\n", ex.f, ex.k);
  }
}


MSVC 10 нормально компилирует, GCC 4.5.1 - отказывается, заявляя
Код: sql
1.
2.
3.
4.
5.
aaa.cpp: In function `int main()':
aaa.cpp:26: error: no matching function for call to `b::b(b)'
aaa.cpp:11: note: candidates are: b::b(b&)
aaa.cpp:14: note:                 b::b(int)
aaa.cpp:26: error:   in thrown expression


К чему бы это?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 01:52
    #38272970
throw class
В вашем случае GCC видимо не использует оптимизацию и при вызове throw b(3); пытается лишний раз скопировать это значение. Ну а так как конструктора копирования у b нет то и выдает ошибку.

В чем проблема сделать так?
Код: plaintext
1.
2.
3.
4.
5.
try
   {
    b ex(3)
    throw ex;
   }
...
Рейтинг: 0 / 0
25.05.2013, 03:00
    #38272981
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Если копнуть глубже, то проблема спровоцирована тем, что наличие юзерского конструктора базового класса a(a& o) не дает компилятору автоматически сгенерировать конструктор копирования a(const a& o) и как следствие также невозможно сгенерировать конструктор копирования наследника b(const b& o).
Поэтому копирование временного объекта b(3) невозможно (почему компилятор вообще захотел его копировать - отдельный вопрос).
Правильным решением думаю будет объявить явный конструктор копирования a(const a& o).
Тогда b(const b& o) будет сгенерирован автоматически, и можно будет использовать форму throw b(3)
...
Рейтинг: 0 / 0
25.05.2013, 11:48
    #38273049
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
не использует оптимизациюВ чем проблема сделать так?
Хм, так действительно работает, хоть и копирует объект лишний раз.

Anatoly MoskovskyПоэтому копирование временного объекта b(3) невозможно

А почему компилятор отказывается использовать для копирования конструктор a(a& o)?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 13:28
    #38273096
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry SibiryakovА почему компилятор отказывается использовать для копирования конструктор a(a& o)?
На временные или константные объекты нельзя ссылаться через неконстантные ссылки.
...
Рейтинг: 0 / 0
25.05.2013, 13:59
    #38273107
throw class
Anatoly MoskovskyDimitry SibiryakovА почему компилятор отказывается использовать для копирования конструктор a(a& o)?
На временные или константные объекты нельзя ссылаться через неконстантные ссылки.
Да. Это MSVC отходит от стандарта и позволяет делать не константные ссылки на временные объекты поэтому первый пример и проходит на нём.
...
Рейтинг: 0 / 0
25.05.2013, 14:10
    #38273115
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Anatoly MoskovskyНа временные или константные объекты нельзя ссылаться через
неконстантные ссылки.
Фишка, однако, ещё и в том, что когда я объявляю copy constructor с const, то всё
компилируется и работает, но этот конструктор не вызывается.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 14:17
    #38273121
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry SibiryakovФишка, однако, ещё и в том, что когда я объявляю copy constructor с const, то всё
компилируется и работает, но этот конструктор не вызывается.
Это можно объяснить тем, что по стандарту программа дожна быть написана так, как будто никакой оптимизации нет. Но компилятор имеет право для оптимизации убирать копирование через промежуточные объекты.
Т.е. компилятор не мог откомпилировать потому что не было конструктора копирования, но как только конструктор добавили - компилятор смог соптимизировать лишнее копирование.
...
Рейтинг: 0 / 0
25.05.2013, 14:21
    #38273122
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Anatoly MoskovskyТ.е. компилятор не мог откомпилировать потому что не было
конструктора копирования, но как только конструктор добавили - компилятор смог
соптимизировать лишнее копирование.
Странные люди сидят в комитетах по стандартам...

Ещё вопрос: в таком случае насколько безопасно в конструкторе снимать константность при
помощи const_cast чтобы изменить что-то в исходном объекте?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 14:30
    #38273124
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry SibiryakovСтранные люди сидят в комитетах по стандартам...
А на мой взгляд это очень логичное и удобное правило.
Dimitry SibiryakovЕщё вопрос: в таком случае насколько безопасно в конструкторе снимать константность при
помощи const_cast чтобы изменить что-то в исходном объекте?
Проблема заключается в том что в такой конструктор могут попасть не только временные объекты, но и по настоящему константные (чей владелец не предполагает что они кем-то могут быть изменены).
Так что если вы можете гарантировать отсутствие константных объектов - то вполне безопасно. Иначе - нет.

Если у вас С++11, то полностью безопасное решения этого вопроса (семантика перемещения) реализуется через rvalue-ссылки (&&).

Для компиляторов до С++11 в Бусте есть библиотека Boost.Move которая помогает реализовать семантику перемещения.
Но я ее никогда не использовал и не могу сказать что она умеет и как это выглядит в коде.
...
Рейтинг: 0 / 0
25.05.2013, 15:03
    #38273142
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Anatoly MoskovskyА на мой взгляд это очень логичное и удобное правило.

По поводу константных объектов - согласн, но приравнивать к ним временные...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 16:29
    #38273190
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry SibiryakovПо поводу константных объектов - согласн, но приравнивать к ним временные...
Их никто не приравнивает.
Вы шо-то неправильно поняли.
...
Рейтинг: 0 / 0
25.05.2013, 17:07
    #38273209
NekZ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Эммм... Извиняюсь, конечно... А деструктор разве не надо объявить виртуальным в этом случае?
...
Рейтинг: 0 / 0
25.05.2013, 17:31
    #38273222
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
NekZЭммм... Извиняюсь, конечно... А деструктор разве не надо объявить виртуальным в этом случае?
В этом случае - не обязательно.
...
Рейтинг: 0 / 0
25.05.2013, 17:37
    #38273224
throw class
NekZЭммм... Извиняюсь, конечно... А деструктор разве не надо объявить виртуальным в этом случае?
Зачем? Полиморфизм тут не используется, никто не создает динамически объект класса b, не хранит указатель типа класса a и не удаляет через него.

Хотя он тут и не помешает, но и не поможет ничем.
А советы - в общем случае всегда делать деструктор виртуальным - тоже от балды, особенно когда хранятся массивы из миллионов объектов подобных классов.
...
Рейтинг: 0 / 0
25.05.2013, 17:57
    #38273228
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Anatoly MoskovskyИх никто не приравнивает.
Вы шо-то неправильно поняли.
Возможно. Но что именно:
Anatoly MoskovskyНа временные или константные объекты нельзя ссылаться через
неконстантные ссылки.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 18:03
    #38273230
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry Sibiryakov,

А в переменную типа int нельзя записать строку или список.
По вашей логике получается что строки приравнены к спискам.
...
Рейтинг: 0 / 0
25.05.2013, 18:09
    #38273233
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Anatoly MoskovskyПо вашей логике получается что строки приравнены к спискам.

А по вашей логике получается, что тип у временного объекта отличается от "обычного" так же
как целое от строки.
Ну да против объективной реальности всяко не попрёшь... Раз GCC говорит, что отличается,
значит отличается.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.05.2013, 20:12
    #38273295
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
throw class
Dimitry SibiryakovА по вашей логике получается
Не надо про мою логику. Давайте про С++.
Временные и константные объекты в С++ не приравнены.
Из того утвеждения, из которого вы сделали вывод, что они приравнены, это не следует.
Что тут не понятно-то?
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / throw class / 19 сообщений из 19, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]