I was writing a test case out to tackle a bigger problem in my application. I ended trying some code out on codepad and discovered that some code that compiled on my local machine (g++ 4.4.1, with -Wall) didn’t compile on codepad (g++ 4.1.2), even though my local machine has a newer version of g++.
Codepad calls this a reference to reference error, which I looked up and found a litle information on. It looks like it’s not a good idea to have a stl container of references. Does this mean I need to define my own PairPages class? And if this is the case, why did it compile locally in the first place? What’s going on?
codepad link: http://codepad.org/UAaJI1rl
#include <deque>
#include <utility>
#include <iostream>
using namespace std;
class Page {
public:
Page() : number_(++count) {}
int getNum() const { return number_; }
private:
static int count;
int number_;
};
int Page::count = 0;
class Book {
public:
Book() : currPageIdx_(3) {
int numPages = 5;
while (numPages > 0) {
pages_.push_back(Page());
numPages--; // oops
}
}
pair<const Page&, const Page&> currPages() { return pagesAt(currPageIdx_); }
pair<const Page&, const Page&> pagesAt(int pageNo) { return make_pair(pages_[pageNo - 1], pages_[pageNo]); }
//const Page& currPages() { return pagesAt(currPageIdx_); }
//const Page& pagesAt(int pageNo);
private:
deque<Page> pages_;
int currPageIdx_;
};
int main() {
Book book;
cout << book.pagesAt(3).first.getNum() << endl;
cout << book.currPages().first.getNum() << endl;
}
A
vector(or any STL container) of references is indeed a bad idea, as obvious when you simply look at requirements for element typeTof any STL container (ISO C++03 23.1[lib.container.requirements]). It starts off by saying that “containers are objects that store other objects”. We can stop right here, because a reference is not an object in C++ (unlike, say, a pointer; note that “object” in C++ parlance doesn’t mean “instance of class”!). But, furthermore, it requiresTto beAssignable, the requirements for which refer to typeT&– ifTis itself some reference typeU&, then the constructed type would beU& &, which (reference to reference) is illegal in C++.If you really want to have a container that doesn’t manage lifetimes of objects, then you should use a container of pointers. If you prefer the safety of references (e.g. lack of pointer arithmetic and null value), you can use
std::tr1::reference_wrapper<T>class, which is copy constructible and assignable wrapper for a reference.