C ++ Возврат по ссылке - PullRequest
       14

C ++ Возврат по ссылке

1 голос
/ 05 апреля 2010

Скажем, у меня есть функция, которая возвращает ссылку, и я хочу убедиться, что вызывающая сторона получает ее только как ссылку и не должна получать ее как копию.Возможно ли это в C ++?

Чтобы быть более понятным.У меня есть такой класс.

class A
{
private:
    std::vector<int>  m_value;
    A(A& a){ m_value = a.m_value; }

public:
    A() {}
    std::vector<int>& get_value() { return m_value; }
};

int main()
{
    A a;
    std::vector<int> x = a.get_value();
    x.push_back(-1);
    std::vector<int>& y = a.get_value();
    std::cout << y.size();

    return 0;
}

Спасибо, Гокул.

Ответы [ 5 ]

13 голосов
/ 05 апреля 2010

Вы можете делать то, что вы хотите для своих собственных классов, делая класс не копируемым.

Вы можете сделать класс недоступным для копирования, поместив конструктор копирования и оператор = в качестве закрытых или защищенных членов.

class C
{
private:
  C(const C& other); 
  const C& operator=(const C&);

};

Есть хороший пример создания NonCopyable класса , который вы можете использовать для своих собственных типов.

Если вы используете boost, вы также можете использовать boost :: noncopyable .

Альтернативное решение:

Другое решение состоит в том, чтобы иметь возвращаемый тип void и заставить вызывающего передать свою переменную по ссылке. Таким образом, копия не будет сделана, поскольку вы получаете ссылку на объект вызывающей стороны.

3 голосов
/ 06 апреля 2010

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

  1. это ошибка , сделанная вызывающей стороной, потому что объект никогда не должен копироваться (в этом случае тип возвращаемого значения, вероятно, не должен был быть скопирован в первое место) или
  2. это не имеет значения для вызывающего абонента, потому что функция вызывается только один раз в неделю (в этом случае вы не должны пытаться нанести ущерб вашему код звонящего ) или
  3. это довольно тупой недосмотр на стороне вызывающей стороны (в этом случае ошибка будет обнаружена с помощью profiling ).

Для # 1 вы либо возвращаете свой собственный тип, либо вы можете обернуть любой свой возврат в свой собственный тип. Обратите внимание, что единственная разница между # 2 и # 3 заключается в релевантности - и , если это релевантно, профилирование найдет его.

IMO, вы не должны калечить свой код, возвращая указатель, когда вам нужна ссылка. Опытные программисты, увидев указатель, сразу же спросят, нужно ли им проверять возвращаемое значение NULL, распределяется ли объект динамически и, если да, кто отвечает за его очистку.

Вы также не должны слепо запрещать копирование того, что вы возвращаете, если вы не можете исключить возможность того, что копирование необходимо.

В конце концов, это старый девиз, который C ++ унаследовал от C: доверяйте своим пользователям знать, что они делают.

1 голос
/ 07 мая 2013

В C ++ 11 вы можете предотвратить вызов конструктора копирования, удалив его:

class A{
    public:
    A(const A&) = delete;
}
1 голос
/ 05 апреля 2010

Это "зависит". Да, вы можете скрыть конструктор копирования (и оператор присваивания), и ваш объект станет недоступным для копирования:

struct foo
{
private:
    foo(const foo&); // dont define
    foo& operator=(const foo&); // dont define
}:

Но если вас интересует одна конкретная функция (то есть обычно копируемая, но не для этой функции), нет. На самом деле, что вы можете сделать с вызывающим абонентом в любом случае?

const foo& f = get_foo(); // okay, by reference, but...

foo f2 = foo(foo(foo(foo(foo(foo(f)))))); // :[

Если ваш собеседник хочет что-то сделать, вы мало что можете сделать, чтобы остановить это.

0 голосов
/ 06 апреля 2010

Вы пытаетесь предотвратить общую опечатку, которая приводит к случайному копированию больших объектов? Если это так, вы можете вместо этого вернуть указатель . Оставить & довольно легко, но для копирования объекта из указателя требуется немного усилий. OTOH, результирующий код будет более уродливым, так что решать, стоит ли оно того

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...