Как правильно передать необработанные указатели от объекта большего размера к объекту меньшего размера, чтобы сделать что-то специализированное? - PullRequest
0 голосов
/ 29 апреля 2020

Я использую библиотеку C из C ++ и, следовательно, я имею дело со многими необработанными указателями. Я хочу создать указатель на объект (например, A), а затем передать указатель на другой объект (например, B) для выполнения чего-то специализированного с. Затем я хочу, чтобы жизнь Б закончилась, но А продолжала делать другие вещи с указателем.

Следующий код выдает ошибку double free or corruption и затем завершается с кодом 139. Однако, когда я удаляю деструкторы, этого не происходит (что не имеет для меня большого смысла, поскольку я думал, что любой объект, использующий необработанные указатели, должен реализовывать свой собственный деструктор для приведения в порядок после себя).

Почему это происходит и есть ли лучшая стратегия для достижения вышеизложенного?

#include <iostream>
#include <sstream>

using namespace std;


struct World { // potentially containing a large amount of data
    int a;
    int b;
    const char *c;
};


class B {
private:
    World *world_;

public:
    std::string doSomethingCleverWithWorld(){
        std::ostringstream os;
        os << world_->c << " = " << world_->a + world_->b <<std::endl;
        return os.str();
    }

    explicit B(World *world) {
        world_ = world;
    }

    ~B(){
        // I want the pointer to world_ to persist after use of B
//        delete world_;
    }
};

class A {
private:
    World *world_;

public:
    explicit A(World *world) {
        world_ = world;
    }

    ~A() {
        delete world_;
    }

    A(const A &a) {
        this->world_ = a.world_;
    }

    A(A &&a) noexcept {
        this->world_ = a.world_;
    }

    A &operator=(const A &a) {
        if (this != &a) {
            this->world_ = a.world_;
        }
        return *this;
    }

    A &operator=(A &&a) noexcept {
        if (this != &a) {
            this->world_ = a.world_;
        }
        return *this;
    }

    std::string doCleverStuff(){
        B b(world_);
        return b.doSomethingCleverWithWorld();
    }

};


int main() {
    World world{
        4, 6, "stuff"
    };

    A a(&world);
    std::string clever = a.doCleverStuff();
    std::cout << clever << std::endl;

    return 0;
};

Выход

stuff = 10

double free or corruption (out)

Process finished with exit code 134

1 Ответ

0 голосов
/ 29 апреля 2020

Просто чтобы обернуть все комментарии - данные могут быть размещены в куче и в стеке. Выделения в куче выполняются с использованием new и освобождаются с использованием delete (или malloc() и free() в C; удаление вызовет деструктор и освободит память, а free просто освободит память).

Когда вы создаете локальную переменную (а ваш экземпляр World является локальной для функции main()), ваши данные будут создаваться в стеке и будут жить до конца области, в которой они были созданы - что в вашем случае является областью действия функции main(). Вы можете управлять только памятью, выделенной динамически (в куче), и попытки сделать это с памятью, выделенной в стеке, приведут к проблеме, с которой вы столкнулись.

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