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

Насколько я знаю, с помощью move можно переместить значение одной переменной в другую, без копирования и избегая вызова деструктора при выходе из области видимости перемещаемой переменной. Возможно ли то же самое, но с указателем на область памяти? Обычному указателю можно присвоить ссылку на область памяти элемента, но проблема в том, что при выходе из области видимости этого элемента вызывается деструктор. Этого можно избежать с помощью динамического выделения памяти, но по некоторым причинам в данной ситуации его хочется избежать. Вопрос в том, возможно ли присвоить указателю область памяти, в которой лежит значение перемещаемой переменной, но при этом избежать вызова дестуктора при выходе из области памяти перемещаемой переменной?

Вот пример, в котором вызывается деструктор, возможно ли в данном примере этого избежать ?

class test{
public:
    int size;
    char* a;
    test(int num);
    test(test & other);
    ~test();

};

test::test(int num){
    a = new char[num];
    size = num;
    for (int i = 0; i < num; i++){
        a[i] = 'a';
    }
}

test::test(test &other){
    a = new char[other.size];
    size = other.size;
    for (int i = 0; i < size; i++){
        a[i] = other.a[i];
    }
}

test::~test(){
    delete [] a;
}

int main()
{
    void* ptr = nullptr;
    for (int i = 0; i < 1; i++){
        test a(3);
        ptr = &a;
    }

    return 0;
}

Ответы (1 шт):

Автор решения: KoVadim

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

Ваш конструктор перемещения будет где то такой

test::test(test&& other)
{
    if (&other != this) {
        std::cout << "ctor(&&)\n";
        this->size = other.size;
        this->a = other.a;
        other.a = nullptr;
        other.size = 0;
    }
}

Также, посмотрите внимательно на свой конструктор копирования - параметр должен быть константной ссылкой.

И не забывайте о операторах копирования/перемещения - в целом - о правиле пяти

Посмотрел ещё раз на main. Тут есть одна плохая штука

int main()
{
    void* ptr = nullptr;
    for (int i = 0; i < 1; i++){
        test a(3); // здесь объект создали
        ptr = &a; // запомнили его адрес
    }
   // по выходу с блока (скопа) объект a будет разрушен. и указатель ptr будет указывать в пустоту
   // move конструктор тут не поможет. тут нужно решить, что хочется

}

переписываем (оно правда не компилится, потому что нужны все конструкторы и операторы копирования/перемещения, но к задаче это пока не относится).

int main()
{
    test ptr;
    for (int i = 0; i < 1; i++){
        test a(3); 
        ptr = std::move(a);
    }

Но тут есть лишнее создание объекта. Плохо.

Есть решение лучше - умные указатели. Как раз то, что нужно

std::shared_ptr<test> ptr;
for (int i = 0; i < 1; i++){
    std::shared_ptr<test> a = std::make_shared<test>(3);
    ptr = a;
}
// теперь здесь ptr доступен и работает.
→ Ссылка