Указатели на указатели очень часто используются в качестве параметров, которые выделяют и возвращают буфер, такой как строка:
void SetValue(char** buf)
{
string s = "Hello, Ptr Ref";
*buf = new char[s.length()+1];
copy(s.begin(), s.end(), *buf);
(*buf)[s.length()] = 0;
}
int main()
{
char* buf = 0;
SetValue(&buf);
cout << buf;
delete [] buf;
return 0;
}
Аналогично, вместо того, чтобы передавать указатель на указатель на буфер, который вы хотите выделить и изменить, вы можете передать ссылку на этот буфер. Это может помочь выяснить семантику вашей функции для вызывающей стороны, чтобы они не делали что-то вроде вызова SetValue(0);
void SetValue(char*& buf)
{
string s = "Hello, Ptr Ref";
buf = new char[s.length()+1];
copy(s.begin(), s.end(), buf);
buf[s.length()] = 0;
}
int main()
{
char* buf = 0;
SetValue(buf);
cout << buf;
delete [] buf;
return 0;
}
Но даже несмотря на то, что семантика SetValue(char*&)
может быть немного яснее, чем версия SetValue(char**)
, все еще есть возможности для улучшения. На ум приходит вопрос, кому принадлежит полученный указатель.
Имейте в виду, что хотя эти примеры являются упрощенными и надуманными, таких реализаций предостаточно. Во многих из тех случаев, когда это делается, у вас нет выбора - например, при вызове функций WINAPI, таких как FormatMessage () и запросе о выделении буфера. Но во многих других случаях, когда вы пишете эту функцию, будут другие способы снять шкуру с кошки. Возможно, лучшие способы. Такие как:
string GimmeValue()
{
return "Hello, String";
}
Это может быть лучше по ряду причин. (Потенциально) семантически более понятно возвращать значение по значению, чем использовать выходы, такие как указатели на указатели, потому что вопрос о собственности легко решается. Часто лучше избегать использования оператора new в тех случаях, когда переменная, выделенная стеком, будет работать нормально, поскольку вы избегаете потенциальных утечек или дефектов памяти из-за delete
многократного использования буфера.