tags:

views:

268

answers:

4

Say, i have a function which returns a reference and i want to make sure that the caller only gets it as a reference and should not receive it as a copy. Is this possible in C++?

In order to be more clear. I have a class like this.

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.

+12  A: 

You can do what you want for your own classes by making the class non copyable.

You can make an class non copyable by putting the copy constructor and operator= as private or protected members.

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

};

There is a good example of making a NonCopyable class here that you can derive from for your own types.

If you are using boost you can also use boost::noncopyable.

Alt solution:

Another solution is to have a void return type and make the caller pass their variable by reference. That way no copy will be made as you're getting a reference to the caller's object.

Brian R. Bondy
OK. That means, i can't do it for objects of libraries. Right?
Gokul
@Gokul: You can wrap them in your own class I guess and use your own class instead.
Brian R. Bondy
If you are using boost (many of us are) you can just derive from `boost::noncopyable`. Besides offering the expected behavior (a class derived from it cannot be copied) it is self documenting: `class X : boost::noncopyable` is clearly showing intent.
David Rodríguez - dribeas
@David: Thanks for the suggestion, added. I actually do use boost::noncopyable in my own projects.
Brian R. Bondy
+1  A: 

It "depends". Yes, you can hide the copy-constructor (and assignment operator), and your object becomes noncopyable:

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

But if you're wondering about one specific function (i.e., normally copyable, but not for this function), no. In fact, what can you do about the caller anyway?

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

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

If your caller wants to do something, there isn't much you can do to stop it.

GMan
Thanks, i got it.
Gokul
A: 

Are you trying to prevent a common typo that causes large objects to accidentally be copied? If so, you could return by pointer instead. Leaving off an & is pretty easy, but it takes a little bit of effort to copy an object from a pointer. OTOH, the resulting code will be uglier, so it's up to you whether it's worth it.

Kristo
Yes looks like, i have to do that.
Gokul
Never mind ugly, that's debatable, but if I call a function and that returns a pointer to an object I worry about the responsibility for deleting it.
sbi
@sbi, a fat comment in the header file should take care of your worries. In principle though I agree with you. I was merely offering an alternative that hadn't been suggested yet.
Kristo
And why shouldn't that comment not point instead out that copying the result might be expensive?
sbi
+2  A: 

If your function returns a reference to an object that shouldn't have been copied, then your function already has done what it could do to prevent copying. If someone else calls your function and copies the return value, then either

  1. it's an error the caller made, because the object should never be copied (in which case the return type probably shouldn't have been copyable in the first place), or
  2. it's irrelevant for the caller because the function is only called once in a week (in which case you must not try to cripple your callers' code), or
  3. it's a pretty dumb oversight on the side of the caller (in which case the error will be found by profiling).

For #1, either you return have your own type or you can wrap whatever your return in your own type. Note that the only difference between #2 and #3 is the relevance - and if it's relevant, profiling will find it.

IMO you should not cripple your code by returning a pointer when what you need is a reference. Experienced programmers, seeing the pointer, will immediately ask whether they need to check for a NULL return value, whether the object is allocated dynamically and, if so, who is responsible for cleaning it up.

You should also not blindly forbid copying of whatever you return, if you cannot eliminate the possibility that copying is needed.

In the end it's the old motto, which C++ inherited from C: Trust your users to know what they are doing.

sbi