Функции C ++, принимающие как указатели, так и ссылки - PullRequest
0 голосов
/ 10 апреля 2009

Я пишу библиотеку на C ++ и имею некоторые функции, которые работают с модулями. Пример будет выглядеть так:

void connect(Module *a, Module *b);

Проблема в том, что иногда было бы удобно, если бы функция принимала также ссылки (некоторые модули могут быть размещены в стеке, а некоторые - в куче, и все & s и * скоро станут скучными и грязными). 1004 *

Теперь у меня есть встроенная функция, которая принимает ссылки, превращает их в указатели и вызывает исходную функцию.

inline void connect(Module &a, Module &b){
    connect(&a, &b);
}

Мне не очень нравится это решение, потому что для нескольких дополнительных функций он делает много кода для записи, чтения, компиляции, ...

Еще одна вещь, о которой мы думали, это добавление Module::operator Module *(), которое должно вернуть this.

Что вы думаете об этом? Неужели я не пропустил ни одного эпического провала?

Спасибо.

Ответы [ 8 ]

15 голосов
/ 10 апреля 2009

Почему бы просто не вызвать функцию с

connect(&a, &b);

как в вашей встроенной функции, когда вам нужно вызывать ее со ссылками? Это очень ясно показывает, что функция принимает указатели и что a и b не являются указателями. Вам нужно всего лишь ввести еще два символа.

8 голосов
/ 10 апреля 2009

Каждый раз, когда вы используете перегрузку оператора, вы повышаете вероятность эпического сбоя. Проблема в том, что вы знаете, что вы не имеете в виду * как стандартный оператор указателя, но кто-то наивно читает ваш код - нет.

Лучшее решение - вернуться и реорганизовать / переосмыслить свой код, чтобы вам не понадобилось два интерфейса для одной и той же операции,

6 голосов
/ 10 апреля 2009

Я не уверен, что это хорошая идея в вашем случае, но, как правило, вы можете использовать адаптер аргументов:

struct ModulePtrOrRef
{
  Module * m_p;
  Module(Module * p) : m_p(p) {}
  Module(Module & p) : m_p(&p) {}
}

void connect(ModulePtrOrRef a, ModulePtrOrRef b)
{
  connect_impl(a.m_p, b.m_p);
}
4 голосов
/ 10 апреля 2009

Как вы заметили, вы можете перегружать функцию, чтобы получать либо указатели, либо ссылки, но я бы не стал делать это по соображениям удобства и придерживался одной функции - так работают все основные библиотеки.

Какой тип аргумента использовать в этой функции? Это зависит от моих личных указаний:

  • Если объект NULL может иметь смысл, используйте указатели.

  • Если в общем случае использования передаваемые объекты обычно создаются динамически, используйте указатели.

  • Если в реализации используются указатели внутри, используйте указатели.

  • В противном случае используйте ссылки.

3 голосов
/ 10 апреля 2009

Я всегда следую соглашению, указанному в руководстве по стилю Google C ++:

http://google -styleguide.googlecode.com / SVN / багажник / cppguide.xml # Reference_Arguments

Что в основном говорит использовать только const &, и * для всего остального. Я думаю, это помогает очень четко определить, какие параметры являются входными данными, которые нельзя изменить (const & 's), и какие вещи будут изменены (*) Если вы следуете такому соглашению, вы можете не копаться в исходном коде.

Указатели на самом деле совсем не плохи, поэтому нет причин избегать их. Фактически, большую часть времени это будет означать только использование "->" вместо "." к разыменованию, которое выглядит круче и стоит того, чтобы написать более понятный код.

1 голос
/ 10 апреля 2009

Причина, по которой вам нужны две функции, заключается в том, что указатель на модуль принципиально отличается от типа «ссылка на модуль». Обойти это невозможно.

Для меня указатели плохие. Всегда. Используйте их, только если вам нужен адрес чего-то, а не ссылка на что-то. И редко вам нужен фактический адрес объекта. Я бы сделал следующее:

  1. Превратить основанную на указателе функцию в справочную функцию.
  2. Прекратите использовать указатели там, где это не нужно. Вам, безусловно, следует избегать указателей и ссылок.

Кроме того, вы можете исследовать константу.

1 голос
/ 10 апреля 2009

Я бы очень неохотно сделал что-то подобное - скорее всего, это был бы запутанный интерфейс для использования.

В общем, я бы предпочел интерфейс, который использует константные ссылки, но если переданный объект будет изменен, я предпочитаю указатели, а не неконстантные ссылки, потому что он дает пользователю интерфейса указание, что объект является переданный может быть изменен.

0 голосов
/ 10 апреля 2009

Я бы избегал встроенного в публичном API.

const & является предпочтительным, когда это возможно, по сравнению с & или *

Я понятия не имею, как эти вещи будут связаны или какое отношение имеет 'a' к 'b'

void connect(Module *a, Module *b);

Имеет ли смысл перестроить интерфейс модуля, чтобы он был более явным

Module a;
a.connectOutput(b);

присвоение имен вашим параметрам помогает в контексте;)

...