О операции удаления в C ++ [duplicate]

Я думаю, что предоставленные ответы вводят в заблуждение. Свойство, определенное внутри класса, становится свойством экземпляра, когда объект создается, независимо от того, как вы его определяете. Таким образом, копии a.list сделаны, а x.list и y.list - разные копии. Причина, по которой они кажутся одинаковыми, заключается в том, что они оба являются псевдонимами в том же списке. Но это следствие того, как работают списки, а не того, как работают классы. Если бы вы делали то же самое с числами вместо списков (или просто используя + = вместо append, что создало бы новый список), вы увидите, что изменение x.attr не влияет на изменение y.attr.

Определяет self.list внутри __init__, потому что функция вызывается дважды, один раз для каждого экземпляра объекта, и поэтому создается два разных списка.

0
задан Brian Tompsett - 汤莱恩 25 August 2015 в 17:34
поделиться

5 ответов

Итак, мой вопрос: почему я все еще могу назвать Go_XXX_Your_Self () и Identify_Your_Self () даже после удаления объекта?

Из-за undefined behavior .

Как это работает на C ++? (есть ли даже после его удаления?)

Из-за неопределенного поведения . Нет гарантии, что он будет работать одинаково на других реализациях. Опять же, неопределенное поведение .

Также вы можете проверить, нет ли там этого? (Я знаю, что теоретически невозможно, но мне любопытно посмотреть, какие методы там)

delete MC1;
MC1 = nullptr;

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

if(my_ptr) {
   // my_ptr is most possibly valid (though you can still go wrong)
   // use my_ptr
}

Аналогичным образом, вы также должны установить raw указатели на nullptr, если они еще не инициализированы каким-либо действительным адресом.

MyClass* some_ptr = nullptr;
...

Но опять же, если у вас есть доступ к современным средствам C ++ 11, гораздо лучше не использовать raw указатели вообще, и просто используйте std::unique_ptr или std::shared_ptr (в зависимости от вашей требуемой семантики). И в будущих стандартных версиях C ++ вы также можете использовать предложенный std::exempt_ptr , который является не владеющей, наблюдательной оболочкой-указателем.

8
ответ дан Mark Garcia 24 August 2018 в 01:19
поделиться

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

С этой целью RAII - это один из способов попытаться уменьшить инциденты этой проблемы.

0
ответ дан Community 24 August 2018 в 01:19
поделиться

Вам не повезло.

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

Доступ к памяти, которую вы delete d, не является чем-то, что вы когда-либо должны делать. В C ++ вы не должны этого делать, потому что компилятор не остановит вас.

0
ответ дан John 24 August 2018 в 01:19
поделиться

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

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

Однако даже при этом вы все равно можете столкнуться с случаями где вы вынуждаете плохие вещи, например:

    std::unique_ptr<Foo> p(new Foo);
    p->foo();
    p.reset(0);
    p->foo();

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

template <typename T>
class CheckedSharedPtr {
    std::shared_ptr<T> ptr_;
public:
    //...
    T * operator -> () const {
        if (ptr_ == 0) {
            //...throw something
        }
        return ptr_.operator->();
    }
};

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

0
ответ дан jxh 24 August 2018 в 01:19
поделиться

Когда вы вызываете delete на объект, память, используемая этим объектом, становится доступной для использования другим использованием new (или, действительно, любым, что использует кучу). До этого времени удаленный объект может (или может not ) сохранить свое предыдущее значение. Но в конце концов, по мере того, как ваша программа будет запущена, память, используемая удаленным объектом , будет перезаписана , а затем, если повезет, произойдет плохая вещь: ваша программа потерпит крах. Если вам не повезло, программа не будет разбиваться, пока она не будет развернута в поле.

2
ответ дан zentrunix 24 August 2018 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: