У меня есть класс, экземпляр которого полностью зависит от обновлений экземпляра отдельного класса. Упрощенный пример:
#include "Source.h"
class ObjectThatNeedsUpdates
{
public:
ObjectThatNeedsUpdates();
void update(const Source& source)
{
//Update member data with data from source
}
private:
//Some member data that needs updating
};
Как видите, каждый раз, когда я вызываю функцию обновления, я передаю константную ссылку класса Source. Но недавно я подумал, что, может быть, было бы логичнее передать ссылку на объект Source только один раз, когда создается ObjectThatNeedsUpdates, и позволить классу хранить ссылку как член, чтобы избежать необходимости передавать источник каждый раз, когда я хочу обновить объект.
Как таковой:
#include "Source.h"
class ObjectThatNeedsUpdates
{
public:
ObjectThatNeedsUpdates(const Source& source)
: source_(source)
{
}
void update()
{
//Update member data with data from source_
}
private:
const Source& Source_;
//Some member data that needs updating
};
Каковы плюсы и минусы этого подхода?
Всякий раз, когда вы думаете об использовании ссылочного члена данных, вам почти всегда лучше использовать член данных указателя. Использование члена ссылочных данных отключает сгенерированное компилятором назначение, и часто невозможно правильно реализовать их самостоятельно. Аналогичные рассуждения применимы к использованию элементов данных const. Обычно лучше реализовать их как private не-const элементы данных и поддерживать инвариантность через интерфейс.
Ссылочный параметр может быть немного более элегантным с точки зрения внутренней инкапсуляции: это нужно только методу update()? - нет необходимости выставлять это как член для других методов. Не беспокойтесь об изменениях Source. Разница в производительности (по сравнению с членом) незначительна. В то время как, если вы занимаетесь shared_ptr, что дорого обходится, вы, в первую очередь, противоречите своей собственной мотивации...
@bloody Я думал, что между указателями и ссылками почти нет разницы в производительности?
@cigien Какой подход вы думаете? Может быть тот, который я представил в своем вопросе?
Хорошо, может быть, я не совсем понял, о чем вы спрашивали. Виноват.
@cigien Не беспокойтесь
Делайте то, что, по вашему мнению, лучше всего выражает контракт между вызывающей стороной update() и самим классом.
Если время жизни ObjectThatNeedsUpdates всегда содержится в пределах времени жизни объекта Source, а используемый объект Source никогда не меняется, то я считаю, что сохранение ссылки на объект Source является лучшим выражением контракта.
Хотя, подумайте о том, чтобы вместо этого держать std::shared_ptr. Это лучше защитит вас от жизненных проблем.
С точки зрения производительности передача ссылки в качестве аргумента функции чрезвычайно дешева (такая же стоимость, как передача указателя, что обычно равно стоимости передачи size_t).
Не думал о пожизненных проблемах, которые могут возникнуть. Спасибо, поменяю на shared_ptr
Во-первых, плюсы и минусы по сравнению с каким подходом? Кроме того, такой вопрос можно считать основанным на мнении. Есть ли у вас какие-то особые опасения по поводу этого подхода?