2010-04-05 4 views
1

Скажем, у меня есть функция, которая возвращает ссылку, и я хочу убедиться, что вызывающий абонент получает ее только как ссылку и не должен получать ее в качестве копии. Возможно ли это на C++?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; 
} 

Thanks, Gokul.

+5

что вы имеете в виду под «абонент получает его в качестве ссылки»? Если функция возвращает ссылку, она возвращает ссылку, а ссылка - это все «вызывающий». Теперь, что делает вызывающий абонент с этой ссылкой, другое дело. Он/она может захотеть создать копию упомянутого объекта. Если вы этого не хотите, сделайте тип объекта не скопированным. – sellibitze

+0

Я хочу сделать эту копию намеренной, и когда они используют функции get, они должны быть вынуждены принимать ссылки компилятором. Но похоже, что это невозможно для классов библиотеки – Gokul

ответ

13

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

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

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

}; 

Существует хороший пример сделать NonCopyable class здесь, что вы можете получить от ваших собственных типов.

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

решение Alt:

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

+0

ОК. Это значит, что я не могу сделать это для объектов библиотек. Правильно? – Gokul

+1

@Gokul: Вы можете обернуть их в свой собственный класс, я думаю, и вместо этого использую ваш собственный класс. –

+0

Если вы используете boost (многие из нас), вы можете просто извлечь из 'boost :: noncopyable'. Помимо предложения ожидаемого поведения (класс, полученный из него, не может быть скопирован), он самодокументируется: «класс X: boost :: noncopyable» явно показывает намерение. –

1

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

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

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

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

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

Если ваш вызывающий абонент хочет что-то сделать, вы не можете сделать это, чтобы остановить его.

+0

Спасибо, я понял. – Gokul

0

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

+0

Да, похоже, я должен это сделать. Не – Gokul

+0

не помните некрасиво, это спорно, но если вызвать функцию и возвращает указатель на объект, я беспокоиться об ответственности за удаление. – sbi

+0

@sbi, толстый комментарий в файле заголовка должен заботиться о ваших заботах.В принципе, хотя я согласен с тобой. Я просто предлагал альтернативу, которая еще не была предложена. –

3

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

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

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

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

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

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

1

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

class A{ 
    public: 
    A(const A&) = delete; 
} 
Смежные вопросы