Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

C++ Frage zur Speicherverwaltung

634  
evgher постоялец17.12.08 14:30
evgher
NEW 17.12.08 14:30 
Moin allerseits,
ich habe folgende Frage zur folgender Situation:
void Options::setActionField(std::string addr)
{
std::string *str = new std::string(addr);
m_action_field = (axis2_char_t *)str->c_str();
}
Der Zeiger *str ist lokal und wird gelöscht sobald die Funktion zu Ende ausgeführt wurde.
Besteht die Möglichkeit die Freigabe über m_action_field durhchzuführen?
etwa
free(m_action_field);
Danke für die Tipps
#1 
Программист постоялец17.12.08 14:58
NEW 17.12.08 14:58 
в ответ evgher 17.12.08 14:30
В ответ на:
Der Zeiger *str ist lokal und wird gelöscht sobald die Funktion zu Ende ausgeführt wurde.

С чего это ты взял? :)
Вообще, как я погляжу, легких путей ты не ищешь :)
Такой странный вопрос: почему m_action_field ты объявил как LPCTSTR, а не как std::string?
#2 
evgher постоялец17.12.08 15:08
evgher
NEW 17.12.08 15:08 
в ответ Программист 17.12.08 14:58, Последний раз изменено 17.12.08 15:39 (evgher)
In Antwort auf:

Вообще, как я погляжу, легких путей ты не ищешь :)

Лёгкий путь я уже нашёл :)
Меня просто именно эта ситуация волновала.
In Antwort auf:

Такой странный вопрос: почему m_action_field ты объявил как LPCTSTR, а не как std::string?

Как ты уже сам намикнул
Мембер-переменная типа Стринг
ну а дальше всё просто:
при выдачи использую Геттер-Метод, который
сразу всё за меня делает
const axis2_char_t *Options::getActionField()
{
return (axis2_char_t *)ms_address_field->c_str();
}
#3 
  femidav завсегдатай17.12.08 16:55
NEW 17.12.08 16:55 
в ответ evgher 17.12.08 14:30
В ответ на:
Der Zeiger *str ist lokal und wird gelöscht sobald die Funktion zu Ende ausgeführt wurde.
Besteht die Möglichkeit die Freigabe über m_action_field durhchzuführen?

Это локальная переменная str будет при выходе из функции уничтожена, а вот резервированный на куче std::string будет болтаться в памяти до конца жизни программы. Утечка памяти налицо.
Законно освободить память по m_action_field ты не можешь. У нас вообще нет гарантий, что str->c_str() показывает на отдельно резервированный кусок памяти. Это может быть просто пуффер внутри std::string (так называемая small string optimization). Так что ты либо будешь пытаться освободить невелидный кусок кучи, либо (если бы у нас все же была возможность освободить память занимаемую str) ты получишь двойную попытку освобождения одного и того же участка кучи.
Для дупликации сишных стрингов используй функцию strdup. Но ещё лучше использовать поля типа std::string. Если же ты используешь поля типа char*, то тебе надо так же правильно имплементировать деструктор, копирующий конструктор и оператор присваивания. Я сомневаюсь, что твоя квалификация позволит тебе это сделать. Поэтому используй std::string, пока не будешь знать язык настолько хорошо, что будешь чётко понимать, когда от него можно отказаться.
Кроме того, не передавай std::string по значению. Это вызывает ненужное копирование параметра. Правильно было бы так: void Options::setActionField(std::string const& addr);
#4 
  femidav завсегдатай17.12.08 17:04
NEW 17.12.08 17:04 
в ответ evgher 17.12.08 15:08
В ответ на:
const axis2_char_t *Options::getActionField()
{
return (axis2_char_t *)ms_address_field->c_str();
}


А вот такого лучше не делать. Если getter отдаёт сишный стринг, то это вызывает неопределённость в вопросе владения оным. Клиент может засомневаться: надо ли мне его уничтожать, или не надо? В итоге кто-нибудь, когда-нибудь его освободит, и вы получите красивенький такой баг. Лучше было бы отдать константную ссылку: std::string const& Options::getActionField();
#5 
  Chipolino свой человек17.12.08 19:14
NEW 17.12.08 19:14 
в ответ evgher 17.12.08 15:08, Последний раз изменено 18.12.08 18:14 (Chipolino)
В ответ на:

const axis2_char_t *Options::getActionField()
{
return (axis2_char_t *)ms_address_field->c_str();
}

Остаётся только добавить , что приведения типов в стиле "С" не кошерны , воспользуйся static_cast<> .
Но в этом случае я бы не рекомендовал возвращать указатель , хоть на константное что-то .
axis2_char_t Options::getActionField()
{
return axis2_char_t (ms_address_field);
}
Конечно должен быть констр . axis2_char_t(const std::string&)
#6 
Simple Nothing is f*cked18.12.08 11:14
Simple
NEW 18.12.08 11:14 
в ответ femidav 17.12.08 16:55
В ответ на:
std::string const& addr

А я всегда пишу
const std::string& addr

Разница есть?

#7 
  femidav завсегдатай18.12.08 11:22
NEW 18.12.08 11:22 
в ответ Simple 18.12.08 11:14
Без разницы, я просто перешёл на форму string const& ради единообразия при обозначении константности указателя.
#8 
evgher постоялец18.12.08 16:26
evgher
18.12.08 16:26 
в ответ femidav 17.12.08 17:04, Последний раз изменено 18.12.08 16:39 (evgher)
In Antwort auf:
А вот такого лучше не делать. Если getter отдаёт сишный стринг, то это вызывает неопределённость в вопросе владения оным. Клиент может засомневаться: надо ли мне его уничтожать, или не надо? В итоге кто-нибудь, когда-нибудь его освободит, и вы получите красивенький такой баг. Лучше было бы отдать константную ссылку: std::string const& Options::getActionField();

Я думаю, что здесь вы не совсем правы.
ms_address_field является мембер-переменной - указателем.
Уничтожение оной будет предпринято только при вызове деструктора - до этого ничего
и не должно освобождаться. Константная ссылка имеет смысл если речь шла о
ссылке, которую - как вы уже правильно приметили - клиент в контексте программы мог бы (он не может (из-за приват)) внезапно освободить.
#9 
evgher постоялец18.12.08 16:38
evgher
NEW 18.12.08 16:38 
в ответ femidav 17.12.08 16:55
In Antwort auf:
Я сомневаюсь, что твоя квалификация позволит тебе это сделать.

Квалификация у меня хватает
Последний год програмировал в Яве и фортране.
Теперь приходиться перестраиваться. В СИ програмировал тоже не мало, а
в СИ++ навыков ещё не очень.
Да и код генерируется автоматически - интерфейсы менять нет смысла.
Какие сигнатуры генерируются - такие и использую, чтобы добавить
нужной функциональности.
Иначи всё сложнее будет.
#10 
  femidav завсегдатай18.12.08 17:02
NEW 18.12.08 17:02 
в ответ evgher 18.12.08 16:38
В плюсах своя специфика, и, исходя из представленного кода, я не вижу её понимания.
Какой код генерируется автоматически? Можно посмотреть на декларацию класса и реализацию перечисленных мною функций?
В ответ на:
Я думаю, что здесь вы не совсем правы. ms_address_field является мембер-переменной - указателем.

Разумееется я прав. Во-первых, почему вообще ms_address_field хранится в классе как указатель? Почему не по значению? Во-вторых, функция возвращает указатель на внутренности поля. Это плохо. Ещё того хуже, что эти внутренности возвращаются в виду указателя. Почему это плохо? Потому имея функцию вида const axis2_char_t *Options::getActionField(), мы не можем по её виду сказать имплементирована ли она так:
const axis2_char_t *Options::getActionField()
{
return (axis2_char_t *)ms_address_field->c_str();
}

или так:

const axis2_char_t *Options::getActionField()
{
return (axis2_char_t *) strdup( ms_address_field->c_str() );
}

Соотвественно мы не знаем, что мы должны делать с данным указателем, то ли потереть его с помощью free, то ли с помощью delete[], то ли оставить всё как есть. Вообще, raw pointer - в большинстве случае есть зло. Есть ссылки, есть значения, есть умные указатели. Обычно этого достаточно. В-третьих, здесь убирается const-qualifier с помощью сишного каста, что не только плохо, но и совершенно излишне.

В ответ на:
Уничтожение оной будет предпринято только при вызове деструктора - до этого ничего

Речь идёт не о том, как это может быть в идеальном случае. А о вот таком случае:
{
Options o;
axis2_char_t const * address = o.getActionField();
delete [] address;
} // приехали...

#11 
  Chipolino свой человек18.12.08 18:11
NEW 18.12.08 18:11 
в ответ femidav 18.12.08 17:02
В ответ на:
Во-первых, почему вообще ms_address_field хранится в классе как указатель? Почему не по значению?

Например для уменьшения зависимостей ( время компиляции )
#12 
evgher постоялец18.12.08 18:38
evgher
NEW 18.12.08 18:38 
в ответ femidav 18.12.08 17:02
функция возвращает указатель на внутренности поля.
ms_address_field как указатель на стринг можно конечно заменить и на сам стринг - и вместо
const axis2_char_t *Options::getActionField(){ return (axis2_char_t *)ms_address_field->c_str();}
вернуть
const axis2_char_t *Options::getActionField(){ return (axis2_char_t *)ms_address_field.c_str();}
In Antwort auf:

Это плохо. Ещё того хуже, что эти внутренности возвращаются в виду указателя.

Банальный вопрос - а почему это плохо?
В чем вообще разница между указателем и референц?
В обоях случаях передаётся адресация поля.
Falls ich davon ausgehe, dass mir die flache Kopie völlig ausreicht, dann erfüllt es
ihren Zweck.
In Antwort auf:

const axis2_char_t *Options::getActionField(){ return (axis2_char_t *)ms_address_field->c_str();}
или так:
const axis2_char_t *Options::getActionField(){ return (axis2_char_t *) strdup( ms_address_field->c_str() );}

Насчёт существования этой версии
const axis2_char_t *Options::getActionField(){ return (axis2_char_t *) strdup( ms_address_field->c_str() );}
я очень сомневаюсь.
In Antwort auf:

Соотвественно мы не знаем, что мы должны делать с данным указателем, то ли потереть его с помощью free, то ли с помощью delete[]

Думаю что знаем. Аллокация произошла с new std::string значит delete[].
Конечно плохо то что потом указатель указывает на поле которого позже может и не быть.
Конечно это только мои доводы. С этим языком я не настолько знаком ...
#13 
  femidav завсегдатай18.12.08 18:41
NEW 18.12.08 18:41 
в ответ Chipolino 18.12.08 18:11
Какие зависимости, это std::string!
#14 
  femidav завсегдатай18.12.08 18:53
NEW 18.12.08 18:53 
в ответ evgher 18.12.08 18:38
В ответ на:
Думаю что знаем. Аллокация произошла с new std::string значит delete[].
Конечно плохо то что потом указатель указывает на поле которого позже может и не быть.

Да, разумеется сейчас, пока пишем, мы это знаем. А через несколько месяцев мы будем это знать? А другой программист использующий данный интерфейс будет это знать?
В ответ на:
Это плохо. Ещё того хуже, что эти внутренности возвращаются в виду указателя. Банальный вопрос - а почему это плохо? В чем вообще разница между указателем и референц?

Указатели плохи, потому что оставляют неясным вопрос владения, если мы передаём ссылку, то всем ясно - этот объект нам не принадлежит. В случае raw pointer никакой ясности нет. Если действительно нужен указатель, то следует использовать умные указатели - shared_ptr и т.п.
Что же касается открытия внутренностей поля - читать теорию OOP (инкапсуляция).
#15 
  sovet знакомое лицо25.12.08 23:37
NEW 25.12.08 23:37 
в ответ evgher 18.12.08 18:38
В ответ на:
В чем вообще разница между указателем и референц?

Над указателем (над его значением, содержимым) можно выполнять операции, а над ссылкой нельзя.
Поэтому указатель обычно используется, если надо сделать что-то типа:
int c = *(my_ptr + 5);
Ну а ссылка используется как учит ООП исключительно для доступа к одному объекту без какой либо возможности получить другие ссылки на другие объекты.
Конечно их функции и роль во многом пересекаются, но это вполне в духе С++.
#16