Как присвоить указателю область памяти переменной, избежав динамического выделения памяти и вызова деструктора
Насколько я знаю, с помощью 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 шт):
Вам нужно написать конструктор перемещения. В этом случае сами данные Вы аккуратно переместите, а то, что будет вызываться деструктор - какая разница - он не будет удалять большой объект.
Ваш конструктор перемещения будет где то такой
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 доступен и работает.