#c
#c
Вопрос:
В настоящее время я сталкиваюсь с проблемой с некоторым управлением памятью в C .
void SomeClass::cpy(char** dest, const char* origin)
{
int len = strlen(origin);
char* tmp = new char[len 1];
strncpy(tmp, origin, len);
tmp[len] = '';
*dest = tmp;
}
Вызов функции выглядит следующим образом
for(auto amp;person : persons)
...
SomeClass::cpy(amp;(person.name_), new_name);
...
Моя проблема заключается в удалении переменной tmp за пределами ее области видимости. Я не могу удалить его в конце этой области, так как мне нужно его значение. Использование деструктора классов с delete[] name_;
, похоже, нарушает память.
Комментарии:
1. Что вы имеете в виду вне его области видимости ?
2. Я настоятельно рекомендую вам использовать
std::string
и ссылаться на параметры вместо того, чтобы возиться с ручными операциями с памятью и указателями.3. Поскольку я выделяю tmp внутри функции, я не могу удалить его из другого места.
4. Прелесть (и ужас) динамического распределения заключается в том, что масштаб — это то, о чем вы говорите.
5. @Mer0winger Уверен, что это так. Вы можете удалить его из любого места, где у вас есть доступ к указателю. Просто убедитесь, что он удален ровно один раз .
Ответ №1:
В современном C считается плохой практикой использовать открытые указатели для владения объектами. Вместо этого используйте std::unique_ptr, что гарантирует освобождение памяти при ее удалении. И предпочтительнее возвращать значение из функций вместо использования выходных аргументов. Измените сигнатуру вашего метода на
std::unique_ptr<char> SomeClass::cpy(const char* origin)
Этот способ std::unique_ptr
будет отвечать за удаление памяти, когда она больше не нужна.
Обратите внимание, что для вашего конкретного варианта использования это std::string
может быть лучшей альтернативой, поскольку оно специально разработано для обработки строк.
Комментарии:
1. В современном C считается плохой практикой использовать открытые указатели , что немного вводит в заблуждение. Использование необработанных указателей- владельцев — плохая практика. указатели, не являющиеся владельцами, просто прекрасны.
Ответ №2:
Быстрый пошаговый:
void SomeClass::cpy(char** dest, const char* origin)
{
int len = strlen(origin);
char* tmp = new char[len 1];
Блок памяти был просто динамически выделен. Этот блок будет существовать до тех пор, пока не будет освобожден вручную с delete[]
помощью .
strncpy(tmp, origin, len);
tmp[len] = '';
*dest = tmp;
Ранее выделенный блок памяти был назначен dest
. Тот, кто предоставил dest
, может использовать delete[]
для освобождения этой памяти в любое время, если это выполняется только один раз за выделение.
}
Теперь вызывающий
SomeClass::cpy(amp;(person.name_), new_name);
указал, что person.name_
и dest
являются одним и тем же. Это означает, что delete[] person.name_;
это вполне приемлемо.
Однако…
Это выглядит как отличное место, чтобы не делать ничего из вышеперечисленного и уменьшить проблемы с управлением памятью std::string
. std::string
заботится о его памяти для вас.
std::string SomeClass::cpy(const char* origin)
{
return std::string(origin);
}
и
person.name_ = SomeClass::cpy(new_name);
Один раз person.name_
преобразуется из char *
в std::string
. Но как только это будет сделано SomeClass::cpy
, это будет излишним, потому что
person.name_ = new_name;
Сделает всю работу за вас.
Комментарии:
1. Вы можете даже создать его и использовать
std::string SomeClass::cpy(std::string origin) { return origin; }
2. @NathanOliver Хороший момент. Также открывается возможность для стяжки длиной в полторы страницы, объясняющей передачу по значению и передачу по ссылке.
Ответ №3:
Вы возвращаете tmp в *dest . Итак, когда вы закончите с этим, вы можете delete person.name_
предположить, что person.name_
это a char*
.