User 13204940 Ответов: 2

Приведение к указателю - управляемое или неуправляемое?


Привет,

Допустим, у меня есть следующий код:
consoleHelper.write_status("Error: " + (char*)gai_strerror(err_code));

Там есть бросок к шару* и нет никакого delete взывал к нему. Эта память каким-то образом управляется автоматически, или вам нужно сделать что-то вроде следующего?
char* cast_ch = (char*)gai_strerror(err_code);
consoleHelper.write_status("Error: " + cast_ch);

delete cast_ch;

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

Что я уже пробовал:

Ничего, просто спрашиваю совета

Richard MacCutchan

Нет, вы не можете удалить его, если только документация для этой функции явно не говорит вам об этом.

2 Ответов

Рейтинг:
6

Richard MacCutchan

Документация (которую вы всегда должны проверять в первую очередь) : gai_strerror[^] говорит вам, что возврат является указателем на символьную константу, поэтому вы ничего не должны с ней делать.


[no name]

Почему же она, будучи const char* то есть ты не должен ничего с ним делать? Я пытаюсь понять причины, по которым эти вещи таковы, каковы они есть.

Richard MacCutchan

Потому что вещь, на которую указывают, - это постоянный иначе говоря , он не может быть изменен. И вы не можете создать константу с помощью new или malloc, так как динамически создаваемое пространство памяти всегда может быть изменено.

[no name]

Итак, указатели const никогда не нужно удалять ни в одном сценарии?

Richard MacCutchan

Это хорошее эмпирическое правило. Хотя использование const иногда может вызвать путаницу, см. Объявление C++ 'const': почему и как[^].

Richard MacCutchan

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

CPallini

Это не совсем так. Пример (по общему признанию, надуманный) :

#include <stdlib.h>
#include <stdio.h>

static char * p = (char *)0;

void init_library();
const char * get_const_string();
void terminate_library();


void init_library()
{
  if ( ! p )
  {
    p = (char * ) malloc(6);
    p[0]='h'; p[1]='e'; p[2] = 'l'; p[3] = 'l'; p[4] = 'o'; p[5] = '\0';
  }
}

void terminate_library()
{
  if ( p ) free (p);
}

const char * get_const_string()
{
  return p;
}

Richard MacCutchan

Ну, вы можете придумать все, что угодно, если очень постараетесь.

CPallini

Действительно. Однако пример кода надуман, а не суть. Мы обычно думаем а const char * указатель обращается к памяти только для чтения, но это не всегда верно.

Richard MacCutchan

Я полностью согласен, но я намеренно избегал этого момента, чтобы попытаться сохранить вещи простыми.

Richard MacCutchan

И конечно же компилятор поймает следующее:

    const char *s = get_const_string();
    s[0] = 'B';

// and ...
    const char *s = get_const_string();
    free (s);

CPallini

Однако это не меняет дела: вы не можете предположить, как на самом деле распределяется строка.

Richard MacCutchan

Нет, но весь смысл заключается в том, что const квалификатор должен помочь вам избежать неосторожных ошибок. Если вы злоупотребляете им, то вы несете ответственность за любые проблемы.

Rick York

Утверждать: "вы не должны ничего с этим делать" - совершенно неверно. Вы можете распечатать его, скопировать и многое другое. Единственное, что вы не можете сделать, это изменить его, потому что это "const." Освобождение или удаление означало бы его изменение, поэтому они не допускаются.

Кроме того, как указано в другом месте, он также не должен быть приведен к непостоянному значению. Для этого есть несколько причин, но одна из них заключается в том, что большинство строковых классов принимают строки символов const, но не неконстантные, так что в вашем случае это не подходит. Я упомянул об этом, потому что в вашем коде есть "consoleHelper.write_status("Error: " + cast_ch")", который выглядит так, как будто вы используете оператор + из класса string для добавления строк, и обычно это не будет работать, если оба аргумента не являются "const char *" или строковыми объектами.

Richard MacCutchan

Я отвечал в контексте того, можно ли использовать free или delete для такого указателя. Другие виды использования идут без слов. И это я сказал, чтобы ты не бросал Конста.

Рейтинг:
19

CPallini

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


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


[no name]

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

CPallini

Библиотека, реализующая gai_strerror функция. Документация такой библиотеки. Если вы не знаете, как выделяется память (и какая среда выполнения C выделила ее), вы не должны ее освобождать.

[no name]

Весь код, кроме gai_strerror, является моим собственным.

CPallini

Строка приходит только из gai_strerror.
Давайте посмотрим правде в глаза: попытка освободить память на таком указателе-это явная ошибка.

[no name]

Но я хочу понять причину *почему*.

CPallini

Тогда вы должны учиться. Отправной точкой могла бы стать эта статья:
https://blogs.msdn.microsoft.com/oldnewthing/20060915-04/?p=29723