43

In my program I have a STL set.

set<string> myStrings;

To improve the efficiency of my code I changed it to hold, only pointers. (I don't need actual string copies to be stored.)

set<string*> myStrings;

I have read that it is a good practice to substitute pointers with references when possible. (Of course, only if the actual functionality of a pointer is not needed.)

set<string&> myStrings;

The latter one gives me a lot of compiler errors, though. Why is it not possible to use references as container elements?

ubuntugod
  • 592
  • 7
  • 16
Julian Lettner
  • 3,309
  • 7
  • 32
  • 49
  • 2
    Consider using a smart pointer like `shared_ptr` (or, if your implementation supports rvalue references, `unique_ptr`, though from your problem description it doesn't sound like that's what you're looking for). – James McNellis Oct 24 '10 at 23:10
  • 2
    An aside: IMHO, "substituting pointers with references when possible" is usually a waste of time, because they're so much more limited, and will inevitably lead you to swapping them all back when you realise later that you need them to be NULL, or to re-seat them, or whatever. The only reason that references are really needed is to make certain operator overloads look syntactically pleasant. – Oliver Charlesworth Oct 24 '10 at 23:23
  • 2
    What makes you think that storing pointers to strings rather than strings is going t o make it more efficient. Modern strings have a very efficient copy mechanism so it is unlikely the gain you get will be significant and the extra complexity it adds to the code will not be worth the gain. – Martin York Oct 24 '10 at 23:27
  • Isn't that the same as passing parameters to functions by value or by refference? – ruslik Oct 24 '10 at 23:45
  • 4
    With c++ 11 you can use std::reference_wrapper to store a references to an object. – Willem D'Haeseleer Apr 11 '13 at 06:32

3 Answers3

58

Containers store objects. References are not objects.

The C++11 specification clearly states (§23.2.1[container.requirements.general]/1):

Containers are objects that store other objects.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 17
    That's not a good answer. Containers in C++ can contain anything, not just objects. For example you can have set, set etc. A reference is a pointer on a physical level, however because the compiler needs to instantiate functions that take references to your element type, and because C++ can't handle double references, set is impossible. – mojuba Oct 24 '10 at 23:19
  • 15
    @mojuba -- In C++, when we say objects, we mean instances of any data type, including builtins. – Benjamin Lindley Oct 24 '10 at 23:24
  • 15
    @mojuba: Both `int` and `int*` are objects (in C++, "an object is a region of storage." (C++03 1.8/1)). A reference is never an object. To quote the C++ standard, "Containers are objects that store other objects" (23.1/1). – James McNellis Oct 24 '10 at 23:25
  • @mojuba: A reference is not an object as far as the language is concerned (although it's probably implemented as a pointer under the hood in certain circumstances). – Oliver Charlesworth Oct 24 '10 at 23:26
  • 1
    @mojuba: References are **NOT** pointers. They are aliases and as such are not objects. Everything else you mention is an object and thus is store-able in a standard container. Even thinking of references as an implementation of pointers is simplistic and often not correct (though I suppose it is an easy way to explain references to a C programmers). – Martin York Oct 24 '10 at 23:28
  • Ok, but the explanation as to why a ref can't be a container element is not that "it's not an object". Just look at the actual error messages given by the compiler. – mojuba Oct 24 '10 at 23:34
  • @mojuba -- read the next two sentences, they give the exact reason. – Benjamin Lindley Oct 24 '10 at 23:38
  • 1
    @PigBen: they give a wrong reason. If you try to compile a program that defines set you will see the exact reason. – mojuba Oct 24 '10 at 23:41
  • 4
    @mojuba -- The errors you get in your compiler are dependent upon the specific implementation of the container provided by your compiler. The standard doesn't mandate any particular implementation. The standard takes a very black box approach. It says things like "The value type of a container must be both copy constructible and assignable", without worrying about how the copying and assigning is being accomplished. – Benjamin Lindley Oct 24 '10 at 23:47
  • 2
    Of course on paper STL is a black box, but I bet all C++ compilers will fail on set for the same reason. We are trying to answer a fairly simple question here, aren't we? Further, references are perfectly constructible and assignable. The only problem with them is that construction and assignment in case of refs have different semantics and plus these operations are ambiguous in case of double refs. That's all. – mojuba Oct 24 '10 at 23:56
  • 3
    @mojuba: No, that's not true. The compile will fail the first place the particular STL implementation tried to use the assignment operation. That could be 20 function calls deep inside the template implementation code, or 2 function calls deep, and still be all well and good w.r.t. the standard. Oh, and no, references are not assignable. – Billy ONeal Oct 25 '10 at 00:00
  • 1
    @mojuba: "We are trying to answer a fairly simple question here, aren't we?" Yes, we are, and this answer provides the answer as clearly as I think is possible: containers store objects that must be assignable and references are neither objects nor assignable. There's really nothing more to it. The "double references" issue you bring up is a red herring; C++0x allows for reference collapsing which resolves that issue but still you cannot have a container of references because references are neither objects nor assignable. – James McNellis Oct 25 '10 at 05:13
  • 2
    @James McNellis: I now agree your answer to the original question is formally correct, but I still don't think it is the best answer that can be given to someone who (obviously) not as experienced in C++. – mojuba Oct 25 '10 at 09:34
23

Not directly relevant to the "why", but to give an answer to the implied desire to do this, I would mention that the c++11 standard library has std::reference_wrapper to enable this. It is implicitly convertible to a reference and it is storable in standard containers.

Zitrax
  • 19,036
  • 20
  • 88
  • 110
Tim Seguine
  • 2,887
  • 25
  • 38
  • 1
    Link to your answer: http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper – leon22 Feb 10 '15 at 08:37
6

As Containers store objects and references are not objects. In case you are at c++ 11, you can use std::reference_wrapper to wrap things to assignable objects.

http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.

Learner
  • 597
  • 1
  • 5
  • 17