C ++: освободить или уничтожить malloc'd char * после захвата локальной строкой? - PullRequest
0 голосов
/ 18 октября 2018

Предположим, я делаю следующее:

char *get_data(...) {
    char *c_style = (char *) malloc(length * sizeof(char));
    load_c_string_with_my_c_function(c_style, length, input);
    return c_style;
}

int main() {
   std::string data(get_data(...));
   // free(data.c_str()); ?? -- are the malloc'd bytes now managed?
   return 0;
}

Есть ли способ освободить память, выделенную get_data()?Будет ли комментарий free(data.c_str()); Работа?

Ответы [ 4 ]

0 голосов
/ 18 октября 2018

Есть ли способ освободить память, выделенную get_data()?

Нет, вы потеряли указатель на нее.

Будет ли комментарийfree(data.c_str()); Работа?

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

Либо использовать std::string повсюду (предпочтительно!)или захватите указатель внутри main first:

int main()
{
   auto cstr = get_data(...);
   std::string data(cstr);
   free(cstr);
}

Проблема в том, что это не исключение для исключительных ситуаций, поэтому у нас есть такие замечательные вещи, как std::string.Это может быть решено с некоторыми либеральными try и catch, но это будет некрасиво.

Кроме того, так как у вас уже есть get_data, предположительно по причине, вы можете рассмотреть string_view болеефактическая память, которую вы уже распределили, если вам действительно не нужно, чтобы data была копией-владельцем.

int main()
{
   auto cstr = get_data(...);
   std::string_view data(cstr);  // no copy! just features
   free(cstr);
}

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

Теперь поэкспериментируйте с тем, чтобы get_data вернул что-то с четкой собственностью и семантикой жизни (std::unique_ptr? std::vector? std::string? .. lol), и вы золотой.

0 голосов
/ 18 октября 2018

Как только вы сделаете

std::string data(get_data(...));

, вы не сможете вернуть указатель, возвращенный get_data(), так что вы потеряете эту память.Чтобы это исправить, просто get_data() верните std::string во-первых, чтобы вам вообще не пришлось беспокоиться об управлении памятью.Это дало бы вам

std::string get_data(...) {
    std::string data(length, '\0');
    load_c_string_with_my_c_function(data.data(), length, input); // requires C++17
    // load_c_string_with_my_c_function(&data[0], length, input); // use this for pre-C++17 compilers
    return data;
}

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

char* ret = get_data(...);
std::string data(ret);
free(ret);
0 голосов
/ 18 октября 2018

Вы не можете удалить указатель, у вас нет ссылки на него.Вам нужно сделать:

int main() {
   char* cstr = get_data(...);
   std::string data(cstr);
   free(cstr);
   return 0;
}

Или гораздо лучше записать свои данные в строку напрямую:

std::string get_data(...) {
    std::string data(length, '\0');
    load_c_string_with_my_c_function(&data[0], data.size(), input);
    return data;
}

Возможно, вам понадобится добавить 1 к длине std::string и /или передать от data.size()-1 до load_c_string_with_my_c_function в зависимости от спецификации length параметра load_c_string_with_my_c_function.

0 голосов
/ 18 октября 2018

Нельзя звонить, звонить free(data.c_str()); или что-то в этом роде.std::string управляет собственной памятью, и даже указатель, полученный из c_str(), автоматически становится недействительным, как только std::string выходит из области видимости.

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

Сделайте это:

int main() {
    char *result = (get_data(...)
    std::string data(result);
    // free(data.c_str()); ?? -- are the malloc'd bytes now managed?
    free(result);
    return 0;
}
...