Можно ли использовать std :: basic_string в качестве оболочки вокруг char *? - PullRequest
7 голосов
/ 22 мая 2019

У меня есть сторонняя библиотека, которая возвращает char * (и wchar_t *), которые созданы в нем strdup (и функциями wcsdup соответственно).

Я хочу избежать вызова free вручную в конце моего кода.

Можно ли написать распределитель для std :: basic_string, чтобы он обрабатывал эти c-строки, возвращаемые этой библиотекой?В идеале я вообще не хочу выделять новую память и использовать возвращенные блоки памяти (предполагается, что строки постоянны).

Ответы [ 4 ]

8 голосов
/ 22 мая 2019

К сожалению, std :: string выполняет свое собственное управление памятью и не может повторно использовать неправильно помещенную строку.

Вы можете скопировать их в std :: string и сразу же удалить их, но это вызовет всеповедения, которые вы пытаетесь избежать.

Что вы можете сделать, это немедленно объявить unique_ptr с пользовательским удалителем.Когда это выйдет из области видимости, он вызовет средство удаления, которое будет free().Между тем, вы можете использовать его так же, как если бы вы использовали необработанный указатель.

std::unique_ptr<char, decltype(free)*> RAII(makeAPICall(), free);

В будущем вы можете создать собственную оболочку для std :: string_view, и, возможно, есть преимущество в прокруткевладеть в краткосрочной перспективе, но если у вас нет более новой библиотеки stdlib (c ++ 17), которая реплицировала все методы для взятия string_view, я считаю, что это бесполезное упражнение.

4 голосов
/ 22 мая 2019

Вы не можете использовать std::basic_string.std::basic_string управляет собственной памятью, поэтому он выделяет новое хранилище и копирует данные в строку.Вам все равно придется вручную освободить хранилище из возвращенного указателя.

Если вы можете использовать C ++ 17, вы можете использовать std::basic_string_view, так как он просто будет содержать копию указателя, но вы столкнетесь ста же проблема, когда вам нужно будет вызвать функцию освобождения вручную для указателя, когда вы закончите с ним.

Что вы можете сделать, это использовать std::unique_ptr или std::shared_ptr с пользовательским средством удаления для хранениявернул указатель из функции, чтобы он автоматически перераспределял память для вас.Затем, если вы можете использовать C ++ 17, вы можете получить std::basic_string_view для этого указателя, чтобы у вас были все строковые функции без необходимости делать копию.В противном случае можно было бы просто использовать функцию c-string из <cstring> для работы с ней или написать собственную версию std::basic_string_view (или найти библиотеку C ++ 11, которая имеет такую, как this )

2 голосов
/ 22 мая 2019

В есть string_view.

template<class T, class Deleter=std::default_delete<T>>
struct string_view_buff : std::string_view<T> {
  std::unique_ptr<T[]> buff;
  explicit string_view_buff( T* in, Deleter d = {} ):
    buff( in, std::move(d) ),
    std::string_view<T>(in) {}
};

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

До этого нет, std::string выделяет и управляет собственной памятью.Вы не можете дать ему буфер и функцию удаления.

2 голосов
/ 22 мая 2019

Я хочу не звонить бесплатно вручную в конце моего кода.

Если библиотека этого не делает, у вас нет способа избежать вызова free (без преднамеренной утечки памяти).

Если сама библиотека не использует строку, то если вы хотите использовать std::string и std::wstring, вы можете использовать конструктор, который принимает CharT* и сразу после создания строки освободите оригинал, используя free.

Если вы хотите избежать дополнительного выделения и копирования, то std::string не вариант.Вы можете использовать умный указатель для освобождения, когда указатель выходит из области видимости.

...