The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"C++ std 11 changes"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Изначальное сообщение [ Отслеживать ]

"C++ std 11 changes"  +/
Сообщение от handler2006 email(ok) on 09-Апр-12, 16:43 
Здравствуйте!
Я, конечно, еще только начинающий специалист в программировании на С++, но меня, однако, удивляет тот факт, что в новом 11 стандарте внесены рад изменений, вызывающих оживленные споры (как и все новое), а некоторые явные неудобства оставлены без изменений. Возьмем конкретный пример с выделением и освобождением памяти:


class A
{
public:
  int *p;
  A::A()
  {
    p = new int;
  }
  A::~A()
  {
    if (p) delete p;
  }
  void set()
  {
    if (p) delete p;
    p = new int;
  }
  void unset()
  {
    if (p) delete p;
    //p = NULL; // without this the program is received SIGSEGV
  }
};

int main()
{
  A a;
  a.set();
  a.unset();
  return 0;
}

Мы создаем объект класса и выделяем память полю класса методом set().
Затем, в некоторый момент времени мы освобождаем память методом unset().
При вызове деструктора если явно не обнулить указатель, он будет удален дважды и программа упадет.
Почему же в новом стандарте среди прочих изменений не добавили обнуление указателя оператором delete ?
Если кто-то считает, что автоматическое обнуление указателя здесь неуместно, пожалуйста, приведите пример, где нам может понадобиться значение указателя после его освобождения - я с такой ситуацией не сталкивался.

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "C++ std 11 changes"  +/
Сообщение от XAnder (ok) on 09-Апр-12, 17:46 
> Почему же в новом стандарте среди прочих изменений не добавили обнуление указателя
> оператором delete ?

Не шибко силён в С++, но полагаю, что это из-за самой природы оператора delete. На скорую руку в Википедии нашёл такое его определение:

void operator delete(void*) throw();

То есть оператору передаётся значение указателя, а не его адрес. А это значит, что оператор не знает, где находится указатель, следовательно и обнулить его не может. И действительно, этот указатель может вообще нигде не "находиться", а быть результатом вычисления какого-либо выражения или вызова функции. Что в таком случае будете обнулять?

PS. Не берусь судить, хорошо это или плохо.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

2. "C++ std 11 changes"  +/
Сообщение от Anonimus (??) on 09-Апр-12, 17:57 
Смотрите в сторону smart pointer, попробуйте применить например unique_ptr для Вашего примера

new и delete достаточно низкоуровневые операции, и одни делают ровно то для чего созданны.

>[оверквотинг удален]
>
> Мы создаем объект класса и выделяем память полю класса методом set().
> Затем, в некоторый момент времени мы освобождаем память методом unset().
> При вызове деструктора если явно не обнулить указатель, он будет удален дважды
> и программа упадет.
> Почему же в новом стандарте среди прочих изменений не добавили обнуление указателя
> оператором delete ?
> Если кто-то считает, что автоматическое обнуление указателя здесь неуместно, пожалуйста,
> приведите пример, где нам может понадобиться значение указателя после его освобождения
> - я с такой ситуацией не сталкивался.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

3. "C++ std 11 changes"  +/
Сообщение от Anon1231 on 09-Апр-12, 18:24 
>[оверквотинг удален]
>
> Мы создаем объект класса и выделяем память полю класса методом set().
> Затем, в некоторый момент времени мы освобождаем память методом unset().
> При вызове деструктора если явно не обнулить указатель, он будет удален дважды
> и программа упадет.
> Почему же в новом стандарте среди прочих изменений не добавили обнуление указателя
> оператором delete ?
> Если кто-то считает, что автоматическое обнуление указателя здесь неуместно, пожалуйста,
> приведите пример, где нам может понадобиться значение указателя после его освобождения
> - я с такой ситуацией не сталкивался.

Почитайте про value type и reference type, многое объяснит.
В Си есть похожая проблема: функция free() не может обнулить свой аргумент, потому что он передаётся по значению.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

4. "C++ std 11 changes"  +/
Сообщение от handler2006 email(ok) on 09-Апр-12, 18:47 
> Почитайте про value type и reference type, многое объяснит.
> В Си есть похожая проблема: функция free() не может обнулить свой аргумент,
> потому что он передаётся по значению.

Думаю, это единственное логическое объяснение такому поведению

Ответить | Правка | ^ к родителю #3 | Наверх | Cообщить модератору

5. "C++ std 11 changes"  +/
Сообщение от elvenic (??) on 09-Апр-12, 19:40 
>> Почитайте про value type и reference type, многое объяснит.
>> В Си есть похожая проблема: функция free() не может обнулить свой аргумент,
>> потому что он передаётся по значению.
> Думаю, это единственное логическое объяснение такому поведению

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

Если вы хотите удобства программирования, как уже тут говорили, есть shared pointers в библиотеке.  Но иногда нужно выжать из процессора максимум, где и одна дополнительная машинная операция на обнуление мешает. Вот дизайн C++ и учитывает подобные вещи.

  

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

6. "C++ std 11 changes"  +/
Сообщение от Anon1231 on 09-Апр-12, 19:54 
>[оверквотинг удален]
>>> потому что он передаётся по значению.
>> Думаю, это единственное логическое объяснение такому поведению
> А также, как я понимаю, комитет по стандарту C++ старается не требовать
> в стандарте языка абсолютно ничего что может привести к утрате эффективности
> и без чего можно обойтись. Требование обнулять указатель добавляет дополнительные команды
> в генерируемый код.
> Если вы хотите удобства программирования, как уже тут говорили, есть shared pointers
> в библиотеке.  Но иногда нужно выжать из процессора максимум, где
> и одна дополнительная машинная операция на обнуление мешает. Вот дизайн C++
> и учитывает подобные вещи.

Я думаю тут дело всё таки не в дополнительной инструкции: объект передаётся по значению, поэтому технически внутри вызываемой функции нельзя изменить значение аргумента в вызвавшей функции.
Даже если бы существовал такой способ, то это не имело бы значения, поскольку Страуструп задумывал С++ как расширение к Си, поэтому подмножество Си нельзя было менять. Поскольку в Си всё передаётся по значению, то и в сишной части С++ пришлось заложить такое поведение.
А вот почему в Си всё передаётся по значению - это вопрос не к комитету и не к Страуструпу, а к Ритчи.

Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

7. "C++ std 11 changes"  +/
Сообщение от elvenic (ok) on 09-Апр-12, 20:45 

> Я думаю тут дело всё таки не в дополнительной инструкции: объект передаётся
> по значению, поэтому технически внутри вызываемой функции нельзя изменить значение аргумента
> в вызвавшей функции.

Теоретически конструкция

  delete ptr;

не есть вызовом функции, и компилятор это обрабатывает не как вызов функции (да, в эту обработку входит вставка кода вызова operator delete() если он определен); поэтому я не вижу технических причин почему бы не потребовать от компилятора вставку кода для обнуления указателя после завершения вызова operator delete().


Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

8. "C++ std 11 changes"  +/
Сообщение от XAnder (ok) on 10-Апр-12, 09:44 
> поэтому я не вижу технических причин почему бы не
> потребовать от компилятора вставку кода для обнуления указателя после завершения вызова
> operator delete().

Повторю свой вопрос: что будете обнулять, если параметр, переданный оператору delete, - это результат вычисления выражения или вызова функции?

Правильный ответ: ничего, поскольку в общем случае компилятор не знает, где лежит этот указатель.

Можно, правда, ввести хитрый delete, так чтобы компилятор ловил простые случаи типа "delete p", когда ясно, что именно нужно обнулить. Но это не спасёт, потому что указателей на один и тот же объект теоретически может быть сколько угодно. Один обнулите, а остальные останутся указателями "в никуда".

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

PS. Она полностью решается столь нелюбимыми многими сборщиками мусора ;-) Да, создавая при этом некоторые новые проблемы, но это уже отдельный разговор.

Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

9. "C++ std 11 changes"  +/
Сообщение от JohnProfic (ok) on 10-Апр-12, 11:33 
> Можно, правда, ввести хитрый delete, так чтобы компилятор ловил простые случаи типа
> "delete p", когда ясно, что именно нужно обнулить. Но это не
> спасёт, потому что указателей на один и тот же объект теоретически
> может быть сколько угодно. Один обнулите, а остальные останутся указателями "в
> никуда".

Я у себя (когда приспичит чего-нить попрограммировать) использую функцию (примерно):


template <typename T>
inline void delete0(T*& ptr) {
    delete ptr;
    ptr = 0; // Да, nullptr тоже хорошо раз уж в теме c++11 :).
}

Понятное дело, это не спасет от множества указателей, но выдаст ошибку компиляции при попытке скормить ей не переменную, а что-то еще.
Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

10. "C++ std 11 changes"  +/
Сообщение от elvenic (??) on 10-Апр-12, 19:50 

> Можно, правда, ввести хитрый delete, так чтобы компилятор ловил простые случаи типа
> "delete p", когда ясно, что именно нужно обнулить. Но это не
> спасёт, потому что указателей на один и тот же объект теоретически
> может быть сколько угодно. Один обнулите, а остальные останутся указателями "в
> никуда".

Так именно такой хитрый delete я и имел в виду. И я абсолютно согласен с тем что это не решит всех проблем.

> PS. Она полностью решается столь нелюбимыми многими сборщиками мусора ;-) Да, создавая
> при этом некоторые новые проблемы, но это уже отдельный разговор.

Или smart pointers - например, boost::shared_ptr/boost::weak_ptr. Недавно я решил использовать boost в одном довольно значительном проекте, включая boost'овские smart poiners - стиль программирования изменился и стал напоминать стиль используемий при работе с Java - намного проще работать с динамической памятью. В общем мне понравилось.  После этого был проект где по разным не зависящим от нас причинам мы не могли использовать boost - так мне оказалось проще напасать свой маленький темплейт-класс shared pointer'а, чем в ручную прослеживать кто сказал new и кто потом должен сказать delete.


Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру