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

#c #c 11 #c 14

#c #c 11 #c 14

Вопрос:

Как мы можем отменить выделение памяти, выделенной в статической функции-члене, используя std::memory_resource::allocate() ?

Я попытался использовать функцию deleter, передающую unique_ptr вместо default_delete . В этом случае это освобождает память распределителя.

Проблемы заключаются в:

  • Я не уверен в продолжительности жизни объекта распределителя до конца unique_ptr выхода из области видимости
  • Я не хочу изменять сигнатуру статической функции ниже формы, используя метод удаления.

например:

 static std::unique_ptr<base,std::functional<void(base*)>> create(std::pmr::memory_resource* all)
  {
    void* ptr = all->allocate(sizeof(base));
    std::unique_ptr<base, std::function<void(base*)> up(new base(), [amp;all] 
     (base* b){ all->deallocate(b,sizeof(base));
    return std::move(up);
  }
  

// Фактический исходный код

 #define _CRTDBG_MAP_ALLOC 
#include <iostream>
#include <memory_resource>
#include <memory>
#include <functional>

using namespace std;

class base
{
  int val = 0;
public:
  base()
  {

  }
  ~base()
  {
    cout << "dest" << endl;
  }
  static std::unique_ptr<base> create(std::pmr::memory_resource* all)
  {
    void* ptr = all->allocate(sizeof(base));
    return std::unique_ptr<base>(new(ptr) base());
  }
};

int main()
{
  {
    {
      std::pmr::memory_resource* all = std::pmr::get_default_resource();
      auto b1 = base::create(all);
      auto b2 = base::create(all);
    }
    _CrtDumpMemoryLeaks();
  }
  return 0;
}
  

Я хочу освободить память, выделенную в статическом методе, без изменения сигнатуры функции (означает добавление функции удаления в unique_ptr ).

Предложите любое решение для решения этой проблемы, и, пожалуйста, также укажите различные способы освобождения памяти, выделенной в этом примере кода с помощью allocate() .

Ответ №1:

Память, выделенная с std::pmr::memory_resource::allocate помощью, должна быть освобождена с помощью std::pmr::memory_resource::deallocate .

Поэтому делать следующее неправильно:

 void* ptr = all->allocate(sizeof(base));
return std::unique_ptr<base>(new(ptr) base());
  

Проблема здесь в том, что unique_ptr будет вызываться delete указатель, удерживаемый ptr , и это недопустимо. С этого момента вы должны предоставить пользовательский параметр удаления, обойти это невозможно.

Поскольку неясно, какую проблему вы хотите решить memory_resource::allocate , на самом деле невозможно сказать, как вы могли бы ее решить. Выделение памяти для каждого объекта кажется, по крайней мере, очень странным и указывает на то, что ваш подход неверен.

Комментарии:

1. void* ptr = all->allocate(sizeof(base)); возвращает std::unique_ptr<base>(new(ptr) base()); почему этот код неправильный? не могли бы вы подробнее объяснить это. Насколько я понимаю, unique_ptr вызовет базовый деструктор, когда он выйдет из области видимости. Мое требование заключается в том, что я должен создать базовый объект внутри статической функции, используя объект распределителя. Объект распределителя будет передан в качестве входного аргумента статической функции. Когда мой unique_ptr выходит за рамки, он должен автоматически освободить память.

2. @Mahendra Как я уже сказал, поведение a по умолчанию unique_ptr заключается в том, что он будет вызывать delete указатель, которым он управляет, и это допустимо только в том случае, если этот указатель был выделен с использованием new . Если вы это сделаете base * b = new(ptr) base() , то вам не разрешено делать delete b , вам разрешено только вызывать деструктор на нем b->~base(); .

3. Я попытался сохранить объект указателя распределителя и объект ptr внутри vector. когда unique_ptr выходит из области видимости, он вызывает деструктор base() . Внутри базового деструктора я освобождаю память, используя объект распределителя, хранящийся внутри vector, и присваиваю ptr-объекту значение null. Но проблема в том, что unique_ptr вызывает исключение после выполнения базового деструктора(). Из этого я понял, что unique_ptr пытается освободить память.например: вектор<std::tuple<база *amp;,Распределитель *>> контейнер для хранения распределителя и базы * .

4. @Mahendra в вашем опубликованном коде вы делаете std::unique_ptr up(new base(), [amp;all](base* b){ all->deallocate(b,sizeof(base)); это в своем примере, который вы вызываете, all->deallocate по указателю, который создается не с all->allocate помощью , а с new base() помощью .