С++ почему двойной указатель для параметра функции out/return?
Я относительно новичок в С++ и работаю над довольно большим проектом на С++. Я замечаю несколько функций, которые принимают двойные указатели как параметры для объектов, которые функция будет создавать в куче. Пример:
int someFunc(MyClass** retObj) {
*retObj = new MyClass();
return 0;
}
Я просто не знаю, почему в этом проекте всегда используются двойные указатели, а не только один указатель? Является ли это в основном семантической подсказкой, что это параметр out/return, или есть ли более техническая причина, которую я не вижу?
Ответы
Ответ 1
Шаблон двойного указателя используется так, чтобы вновь выделенный MyClass
мог быть передан вызывающему. Например
MyClass* pValue;
someFunc(&pValue);
// pValue now contains the newly allocated MyClass
Здесь недостаточно одного указателя, поскольку параметры передаются по значению в С++. Таким образом, модификация одного указателя будет видна только внутри someFunc
.
Примечание. При использовании С++ вы должны использовать ссылку в этом сценарии.
int someFunc(MyClass*& retObj) {
retObj = new MyClass();
return 0;
}
MyClass* pValue;
someFunc(pValue);
Это позволяет передавать аргумент по ссылке вместо значения. Следовательно, результаты видны вызывающему.
Ответ 2
Короткий ответ заключается в том, что параметры в С++ передаются по значению, поэтому ваша функция получает копию этого указателя. После того, как вы перепишете его внутри своей функции, это изменение будет потеряно.
Однако ваш фрагмент хочет, чтобы изменения были видны снаружи, поэтому ему нужен способ перезаписи фактического указателя на объект, поэтому он должен получить копию указателя на указатель на класс, чтобы он мог перезапишите внутренний указатель и увидите его снаружи.
Ответ 3
Эти две звезды (двойной указатель) означают "указатель на указатель". Это способ обойти ограничение, в котором вы не можете вернуть две вещи из функции в С++ (в вашем случае код возврата, указывающий на успех или неудачу, и только что выделенный объект).
Ответ 4
Использование одного указателя просто не сработает. Рассмотрим:
int someFunc(MyClass* retObj) {
retObj = new MyClass();
return 0;
}
MyClass* ptr = null;
someFunc(ptr);
// ptr is still null and we've got a memory leak
Есть способы сделать эту работу иначе, чем использовать указатель на указатель, относительные достоинства которого могут обсуждаться.
Ответ 5
Канонический способ вернуть X - передать указатель на X. Если X является "указателем на MyClass", канонический способ вернуть его - передать "указатель на указатель на MyClass". Вы не можете просто передать указатель на MyClass для функции, потому что вызывающий объект не знает, каково должно быть значение этого указателя.