LINUX.ORG.RU

C++, private деструктор мешает сделать new T[N];, но не мешает new T; Почему?


0

1
#include <iostream>

class XX
{
public:
    XX() {std::cout<<"C XX\n";}
private:
    ~XX() {std::cout<<"~ XX\n";}
};

int main() {
    XX *xx=new XX[10];   // compile error (1)
    XX x_auto;           // compile error (2)

    XX *xx=new XX;       // ok (3)
    delete xx;           // compile error (4)

    return 0;
}

Есть гипотезы.

(1) - ошибка, ибо в случае исключения в конструкторе XX() при конструировании 5-го элемента, компилятор должен будет вызвать (сгенерить код вызова) деструктора ~XX() для предыдущих 4 успешно сконструированных объектов и не сможет этого сделать по причине приватности сего деструктора. Вероятность сего исключения невозможно понять на этапе компиляции, поэтому такое запрещено.

(2) - ошибка, ибо объект x_auto - автоматический (на стеке), что означает неизбежность вызова его деструктора, что невозможно из-за приватности сего деструктора.

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

(4) - ошибка, не могу вызвать деструктор - его нет (приватный, наружу не торчит).

А как ты пришёл к тому, что засунул деструктор в private?
Не могу навскидку придумать зачем бы это могло понадобиться.

Или это просто эсперимент?

Stahl ★★☆
()
Ответ на: комментарий от nerdogeek

Ну синглтоны обычно по-другому используются.
Учитывая main() ТС явно не про синглтон думал.

Я обычно вообще кладу большой и толстый на деструктор в синглтонах. Неоходимости в нём пока не возникало...

Stahl ★★☆
()
Ответ на: комментарий от Stahl

Из гугла выпало, там человек интересовался почему не компилируется. Я не удержался и тоже задумался.

kiverattes ★☆
() автор топика

1 - Если так, компилятор слишком много думает, когда его об этом не просят 2 - Всё верно, код вызова деструктора помещается в конец области видимости, а в случае с закрытым деструктором явный облом 3 - Нормальное поведение компилятора 4 - Да, деструктор можно вызвать только внутри самого класса

anonymous
()
Ответ на: комментарий от anonymous

«Да, деструктор можно вызвать только внутри самого класса»

разумеется имелся ввиду закрытый деструктор, если вдруг что

anonymous
()
Ответ на: комментарий от anonymous

(1) Наверное всё просто: компилятор втыкает умолчательные обработчики исключений. Умолчательный обработчик исключения в случае с массивом объектов подразумевает вызов деструкторов для уже сконструированных объектов. Генерируя такой обработчик, компилятор вдруг сталкивается с конфликтом - невозможность вызова деструктора.

kiverattes ★☆
() автор топика
Ответ на: комментарий от slackwarrior

Не мешай, человек открыл для себя неисчерпаемый источник

...лулзов.

geekless ★★
()
Ответ на: комментарий от r

...геморроя. С++.

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

pathfinder ★★★★
()
Ответ на: комментарий от nerdogeek

От синглтонов больше вреда чем пользы. Можешь сам посмотреть на википедии. Там в плюсах один пункт, а в минусах - два.

nanoolinux ★★★★
()

А если new XX() вызывать?

unC0Rr ★★★★★
()

Может кто еще в спеке что-нибудь найдёт про это?

Или это баг gcc?

KennyMinigun ★★★★★
()
Ответ на: комментарий от kiverattes

Всё же ошибка была бы логичнее в delete [] XX. Какого хрена компилятор генерит код вызова деструктора заранее? Не его собачье дело.

Компилятор, точнее его создатели, слишком много на себя берут, наделяя компилятор функциями багоанализатора. В стандарте это никак не оговорено (массив синглтонов это и правда черезчур экстравагантно), так что UB - да, ошибка - нет.

Выходит это глюк компилятора.

anonymous
()
Ответ на: комментарий от pathfinder

Мне больше нравится сравнение с колюще-режущими и ударно-дробящими инструментами :) По этой логике бензопилы должны быть с резиновыми цепями... И с игрушечным двигателем (резиномотор подойдет) - а то кто-то ногу отпилит.

Но в случае с бензопилами достаточно дисклаймера: идиотам в руки не давать. А в случае с С++ основная причина внезапного отпиливания ног не так очевидна :)

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от anonymous

Даже если в коде всё-таки был delete [] xx , но был убран перед помещением сюда (то есть код вызова деструктора для массива был сгенерирован законно), даже в этом случае на new [] он ругаться просто не должен, это не его ума дело.

anonymous
()
Ответ на: комментарий от anonymous

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

kiverattes ★☆
() автор топика
Последнее исправление: kiverattes (всего исправлений: 1)
Ответ на: комментарий от kiverattes

Почему это не может? Если бы было XX xx[10]; тогда он должен сгенерить код вызова деструктора при выходе из контекста, а с какого перепою он должен его генерировать при вызове new ?

anonymous
()
Ответ на: комментарий от anonymous

Генерация кода - это ещё не вызов кода.

kiverattes ★☆
() автор топика

1) Он как бы должен создать 10 объектов, которые никогда(!!!!) не сможет удалить. Объекты в массиве могут уничтожаться только публичным деструктором.

svu ★★★★★
()

Есть гипотезы.

Всё правильно. Не забудь пометить тему как решённую ;)

const86 ★★★★★
()
Ответ на: комментарий от kiverattes

«когда до этого дойдёт дело по одной из возможных ветвей выполнения, по которой идёт дефолтный обработчик исключения.»

Пусть bad_alloc кидает. Какой ещё нафиг вызов деструктора?

Вот до чего тараканы в головах авторов гцц доводят. Страуструпа на них нет.

anonymous
()
Ответ на: комментарий от kiverattes

А если попробовать свой собственный обработчик исключений запилить? Изменится ли что-нибудь?

svu ★★★★★
()
Ответ на: комментарий от svu

У него нет выбора. Есть ветвь выполнения кода, в которой написано «вызвать деструктор XX». Эта ветвь выполняется, когда происходит исключение при конструировании очередного элемента массива (для удаления тех, которые к тому моменту успели сконструироваться). А раз такая ветвь есть, то компилятор генерирует её код. И тут он обнаруживает, что ветвь нарушает права доступа к деструктору XX::~XX() и поэтому ругается на оператор new[], являющийся родителем для всех этих ветвей.

kiverattes ★☆
() автор топика
Последнее исправление: kiverattes (всего исправлений: 2)
Ответ на: комментарий от pathfinder

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

С++ в таком случае подобен автомобилю без подушек и ремней безопасности, отсутствием защиты пассажира, практически без корпуса и с оголенными проводами. «Перед тем как пользоваться - выберите себе подмножество автомобиля, и обматайте его изолентой. И главное никаких резких поворотов»

r ★★★★★
()
Ответ на: комментарий от anonymous

Как раз, помню, Страус в подобных случаях строго-настрого наказывал кидать исключение, а не вызывать деструктор. Гэцецешники посоветовались с тараканами и решили перекроить крокодила по-своему. Ну что же, не в первый раз.

anonymous
()

Насчёт:

XX *xx=new XX[10];   // compile error (1)

(1) - ошибка, ибо в случае исключения в конструкторе XX() при конструировании 5-го элемента, компилятор должен будет вызвать (сгенерить код вызова) деструктора ~XX() для предыдущих 4 успешно сконструированных объектов и не сможет этого сделать по причине приватности сего деструктора. Вероятность сего исключения невозможно понять на этапе компиляции, поэтому такое запрещено.

Что-то тут не так: я вот выбросил исключение в конструкторе 5-го обьекта, но деструктор ни разу не дёрнут.

http://ideone.com/QW7n4p

Почему тогда XX *xx = new XX[10]; требует доступа к деструктору?

cast geekless

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)

какие то бажные пошли gcc нынче

#include <iostream>
 
class XX
{
public:
    XX() {std::cout<<"C XX\n";}
private:
    ~XX() {std::cout<<"~ XX\n";}
};
 
int main() {
    XX *xx = new XX();  // OK
    XX xx2();  // OK
 
    return 0;
}
x0r ★★★★★
()
Ответ на: комментарий от KennyMinigun

«Что-то тут не так: я вот выбросил исключение в конструкторе 5-го обьекта, но деструктор ни разу не дёрнут.»

Он и не должен не разу дёргаться в конструкторе массива. Но, очевидно, с какого-то непонятного хрена создатели гцц решили код его вызова на всякий случай сформировать, раз на закрытый деструктор он ругается.

anonymous
()
Ответ на: комментарий от kiverattes

Наверное во втором «окей» у вас получилась декларация функции без аргументов, которая возвращает объект XX по значению.

Не-не-не, вот так:

#include <iostream>
 
class XX
{
public:
    XX() {std::cout<<"C XX\n";}
private:
    ~XX() {std::cout<<"~ XX\n";}
};
 
int main() {
    XX *xx = new class XX();  // OK
    XX xx2();  // OK
 
    return 0;
}

Тоже ок: http://ideone.com/w4J7qf

KennyMinigun ★★★★★
()
Ответ на: комментарий от KennyMinigun

Возможно, исключение типа const char*, который вы кинули, не попадает в число тех, на которые срабатывает описанное мной поведение. Я кидал наследника std::exception, попробуйте.

kiverattes ★☆
() автор топика
Ответ на: комментарий от kiverattes

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

x0r ★★★★★
()
Ответ на: комментарий от x0r

Это декларация функции, а не вызов. Она ушла в корзину, т.к. у этой функции нет ни определения, ни вызова её, а только декларация. То есть, пустое место.

kiverattes ★☆
() автор топика
Ответ на: комментарий от anonymous

Ну или два других варианта:

1. Автор не всё сказал

2. У автора глючный гцц

Проверить не могу, у меня под ругой сейчас гцц нету.

anonymous
()
Ответ на: комментарий от kiverattes

А что изменилось? Та же декларация функции xx2(void), возвращающей XX.

Нет. new class XX(); явно указывает семантическому анализатору, что нужно вызвать конструктор а не функцию.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.