Ukio_G
@Ukio_G
Незамысловатый юноша.

Удаление объекта в C++ без создания его через new, или можно ли удалять объекты взятием адреса (&)?

Доброго времени суток всем.
Столкнуться с такой проблемой - надо удалить экземпляр объекта :

BaseClass BaseClassObj;
    /*
            Какой-то не очень важный код, который еще можно будет увидеть ниже.
   */

    // Разумеется это работать не будет ( кстати, очень интересно почему - ведь
    // по идее имя объекта это указатель на него, если у кого будет возможность 
    // объяснить этот момент - буду крайне признателен), ведь мы создали объект 
    // экземпляр объекта не использую new и указатель на объект.
    delete BaseClassObj;


В итоге попробовал такой метод:
BaseClass BaseClassObj;
    /*
            Какой-то не очень важный код, который еще можно будет увидеть ниже.
   */

    // Компилятор уже не ругается, но мы получаем очень интересный вывод в консоль.
    // В итоге если у нас деструктор срабатывает дважды, при одном созданном объекте,
    // один раз сейчас, второй раз после завершения main()
        delete &BaseClassObj;


Интересно получается.
Ниже - код и вывод в консоль, в общем все то, что побудило меня создать эту тему.

main.cpp :
#include "BaseClass.h"
using namespace std;

void BaseClassPresentation(){

    BaseClass BaseClassObj;
    BaseClassObj.Value2 = 15;
    std::cout<<"Value2 after resetting Value2. Get value like BaseClass::Value2 (static member of class) - "<<BaseClass::Value2 << std::endl;

    BaseClassObj.OverloadedFunction(1);
    BaseClassObj.OverloadedFunction(1,2);
    BaseClassObj.OverloadedFunction(13.2, 47.1);

    //  Мы НЕ можем таким образом удалить объект.
    //  Потому что удаление происходит через указатель.
    //  Объект BaseClassObj будет удален только по завершению программы.
    //    delete BaseClassObj;
    // или же....
    // При помощи оператора взятия ссылки (&).
        delete &BaseClassObj;

    //  Код ниже иллюстрирует как создать объект, чтобы его удалить, без использования операции взятия адреса
    BaseClass *BaseClassObjPtr = new BaseClass(2);
    delete BaseClassObjPtr;
}


int main(){
    std::cout<<"Main function start now."<<std::endl;
    BaseClassPresentation();

    return 0;
}


BaseClass.h :

#ifndef KEYWORDS_BASECLASS_H
#define KEYWORDS_BASECLASS_H


#include <iostream>


class BaseClass {
public:
    //    Так делать нельзя. 
    //
    //    static int Value2 = 10;
    static int Value2;
    int Value1 = 50;

    BaseClass() {
        std::cout << "Constructor BaseClass has been called" << std::endl;
    }

    // Конструктор тоже может быть перегружен!
    BaseClass(int a){
        std::cout << "Constructor BaseClass has been called with argument. this->Value1 now is equal " << a << std::endl;
        this->Value1 = a;
    }

    // Это и функции ниже являются ПРОТОТИПАМИ!
    static void StaticFunction();

    // Так делать нельзя, потому что типы аргументов, или количество аргументов должны отличаться
    // в перегруженых функциях, не только возвращаемый тип знеачения.
    // float OverloadedFunction(int a);

    int OverloadedFunction(int a);

    // void OverloadedFunction(int a);
    // Возвращаемый тип перегруженных функций может быть как одинаковый , так и различаться.
    int OverloadedFunction(int a, int b);

    float OverloadedFunction(double a, double b);

    //  Деструктор. Не имеет аргументов. Да и не нужны они ему, на самом деле.
    //  Вызывается при удалении объекта или при закрытии программы.
    //  Так же деструктор НЕ МОЖЕТ быть перегружен и вообще должен быть только один.
    //    ~BaseClass(int a){}

    ~BaseClass(){
        std::cout << "Delete anythig used by BaseClass class" <<std::endl;
    }
};


#endif //KEYWORDS_BASECLASS_H


BaseClass.cpp :
#include "BaseClass.h"



int BaseClass::Value2 = 5;

//Появляется ошибка - cannot declare member function <...> to have static linkage
//Мы не можем объявлять функции статическими, только определять. В данном случае мы как раз ОБЪЯВЛЯЕМ
//В свою очередь ОПРЕДЕЛЯЕМ эту функцию мы в самом теле класса, то есть в файле BaseClass.h
//static void BaseClass::StaticFunction(){              --- НЕ БУДЕТ РАБОТАТЬ. ПОТОМУ ЧТО.
void BaseClass::StaticFunction(){
    std::cout << "Call static function" <<std::endl;
    std::cout << "Static value of variable Value2 - " << Value2 << std::endl;
    Value2 = 10;
    std::cout << "Static value of variable Value2 after new value - " << Value2<< std::endl;
}

int BaseClass::OverloadedFunction(int a) {
    std::cout << "Overloaded function with one argument (int a). Argument value is - " << a << std::endl;
    return 1;
}

int BaseClass::OverloadedFunction(int a, int b) {
    std::cout << "Overloaded function with two integer arguments (int a, int b). Sum arguments - " << a+b << std::endl;
    return 1;
}

float BaseClass::OverloadedFunction(double a, double b) {
    std::cout << "Overloaded function with two double arguments (double a, double b). Division arguments - " << a/b << std::endl;
    return 1.0;
}


Выше уже сказал, но заранее повторюсь - почему мы не можем удалить объект по имени объекта, разве это не есть как раз указатель на объект?

Огромное спасибо всем, кто отпишется по данному вопросу.
  • Вопрос задан
  • 12112 просмотров
Решения вопроса 2
devalone
@devalone
̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻
BaseClass BaseClassObj;
Объект создаётся на стеке и будет уничтожен(просто сдвинут указатель на вершину стека по факту) при выходе из области видимости(функции), попытки удалить его через delete будут приводить к UB, т.е. сказать, что произойдёт нельзя, да и незачем.
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
> Объект BaseClassObj будет удален только по завершению программы.
BaseClass baseClassObj;
Здесь создаётся объект на стеке. Имя — это просто имя объекта. Никаких указателей здесь нет. Как только мы покинем блок (любым образом: штатно выйти, goto, break, выброс аварии — кроме «жёсткого» выхода из программы функциями типа exit), у объекта автоматически исполнится деструктор и прямой вызов не нужен. Блок, то есть подпрограмму BaseClassPresentation.

BaseClass *BaseClassObjPtr = new BaseClass(2);
Здесь BaseClassObjPtr это имя указателя (а не указатель на указатель). Объект создаётся в динамической памяти, и его придётся уничтожать вручную. Многое в Си++11 сделали для того, чтобы подобные объекты уничтожались не вручную, а всё теми же автодеструкторами.
std::unique_ptr<BaseClass> BaseClassObjUp = new BaseClass(2);
Это уже маленький объект со своим деструктором. А в деструкторе находится delete, и он сработает, как только программа выйдет из своего блока.

То, что вы хотите, иногда бывает нужно, и я вижу этому две причины.
1. Объект управляет какими-то сложными и важными ресурсами: большим количеством памяти, файлом, мьютексом… И этот важный ресурс бывает нужно освободить раньше, чем наступит деструктор. Например, у любого файлового потока есть функция close() — она закрывает файл.
2. У нас сложное и хитрое управление памятью, когда приходится использовать placement new и прямой вызов деструктора. Скажу честно, не использовал никогда. Как и 90% программистов на Си++.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы