Функция-член C++ требует указателя, плохая практика для передачи по ссылке?
Если функция-член класса C++ требует указателя на объект в качестве аргумента, считается ли это плохой практикой для передачи по ссылке?
Следующий код, например, будет работать, однако без передачи по ссылке он станет опасным кодом и приведет к катастрофическим ошибкам во время выполнения.
class ClassA
{
public:
void SetPointer(const ClassB& classb) // Remove 1 ampersand and serious errors will occur
{
if(ptr_to_classb == nullptr) // Initialized to nullptr in constructor
ptr_to_classb = &classb;
else
throw(...); // Throw some error
}
private:
ClassB* ptr_to_classb;
}
Подумайте, если передается по значению и была сделана копия аргумента, это будет иметь катастрофические последствия при разыменовании в более позднее время.
Альтернатива заключается в следующем:
class ClassA
{
public:
void SetPointer(const ClassB* const classb)
{
if(ptr_to_classb == nullptr) // Initialized to nullptr in constructor
ptr_to_classb = (ClassB*)(classb);
else
throw(...); // Throw some error
}
private:
ClassB* ptr_to_classb;
}
Мне нравится последовательность, по умолчанию для первого типа, однако я подозреваю, что вторая форма считается лучшей практикой. Это тот случай?
3 ответа
Хорошо, оба подхода верны и хороши, но в вашем случае, вероятно, будет лучше использовать указатели, так как ссылочной переменной может быть присвоено значение только при инициализации, в отличие от указателей. С тем же указателем вы можете позже передать другой объект класса.
На мой взгляд, если передача пустого аргумента в метод является допустимой вещью (то есть логика, которую выполняет метод, будет действительной с нулевым указателем), то используйте указатель. Если аргумент никогда не должен быть нулевым, используйте ссылку.
В вашем случае это зависит от того, действительно ли для ClassA::ptr_to_classb значение null. Так как вы бросаете, если ptr_to_classb уже установлен (то есть вы никогда не захотите изменять то, на что он указывает), вы можете даже рассмотреть возможность сохранения ссылки и передачи ее в конструктор ClassA, избавившись от ClassA::SetPointer.
Здесь есть и другие мнения относительно ссылки против указателя.
Ваш метод просто устанавливает поле вашего объекта, поэтому кажется, что вы хотите использовать тип поля (это указатель, а не ссылка). Вы написали
Мне нравится последовательность, чтобы по умолчанию первый тип
что, я думаю, относится к правилу "используйте ссылки, когда это возможно; используйте указатели в обратном порядке". Я думаю, что ваш случай является исключением из этого правила, потому что декларация
void do_stuff(ClassA& object)
обычно означает "делать что-то на объекте и забыть об этом", и ваш случай отличается.