2

I have the following struct:

struct Transaction {
    Transaction(Book& bb, Patron& pp, Date dd)
        : b(bb), p(pp), d(dd) { }
        Book& b;
        Patron& p
        Date d;
};

When I try to put an object of type Transaction into a vector<Transaction>v_t with a push_back, it won't work. A screenful of errors breaks lose.

Is it because I have references as members of my object?

Robotronx
  • 1,728
  • 2
  • 21
  • 43
  • 1
    Can you show the code you're using for pushing the object into the vector, as well as the errors? – Jason Oct 10 '11 at 14:13
  • References were introduced into C++ to support pass by reference. They were never intended to be used as data members. Although there are *some* valid use cases, you are almost always better off using pointers as data members instead of references. – fredoverflow Oct 10 '11 at 14:46
  • @Fred: "They were never intended to be used as data members." A reference that backs up this claim would be helpful. – John Dibling Oct 10 '11 at 14:47
  • @FredOverflow: Whether something was first created for some purpose does not mean that using it for another is invalid. If that were the case, almost everything in `boost::type_traits` would be invalid (SFINAE almost certainly was not created for the hackish techniques employed in `type_traits`). The standard does explicitly allow references to be used as members. – David Hammen Oct 10 '11 at 15:22
  • 1
    In case you were in any doubt, references in C++ are nothing like references in other languages such as C#, Java, etc. Personally I would advise against using data member references in C++ unless there is a particularly compelling reason to use them. – markh44 Oct 10 '11 at 16:32
  • @mark: I couldn't agree more. – fredoverflow Oct 10 '11 at 17:54

4 Answers4

3

You'll need an assignment and copy operator for the type since it contains a reference. STL container objects must be copyable AND assignable (and this won't be possible with your reference unfortunately).

Check this thread:

http://cboard.cprogramming.com/cplusplus-programming/106779-copy-constructor-class-const-reference-member.html

It discusses the problem and some alternate solutions, though it basically says don't have a reference member in container type.

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
2

STL is value-based and doesn't play well with references. You can get into a horrible tangle trying to get around this rule.

Turn the b, p, d members into values or shared_ptrs.

Community
  • 1
  • 1
spraff
  • 32,570
  • 22
  • 121
  • 229
0

STL doesn't work with references because you can't have assignment operator that will assign a reference(not copy).
You should use pointers instead like:

struct Transaction {
    Transaction(Book& bb, Patron& pp, Date dd)
        : b(&bb), p(&pp), d(dd) { }
        Book* b;
        Patron* p
        Date d;
};
Daniel
  • 30,896
  • 18
  • 85
  • 139
  • That's what I did, but I still wanted to see why it won't work when I have references involved. – Robotronx Oct 10 '11 at 14:43
  • 1
    @user987827: It won't work because the C++ standard library sequence containers must have an assignment operator. You didn't specify an assignment operator, so the compiler tried to create it for you. It couldn't do that because *you can't change a reference*. Think of a reference data member `Book & b;` as very similar to a constant pointer, `Book * const b;` You can't change a const member, either. – David Hammen Oct 10 '11 at 15:26
0

Community wiki, because this almost certainly invokes UB.

If you have a copy constructor you can make an assignment operator using placement new:

struct Transaction {
  Transaction(Book& bb, Patron& pp, Date dd)
    : b(bb), p(pp), d(dd) { }

  Transaction(const Transaction & src)
    : b(src.b), p(src.p), d(src.d) { }

  Transaction & operator= (const Transaction & src) {
    if (this != &src) {
      this->~Transaction();
      Foo * copy = new (this) Transaction(src);
      return *copy;
    } else {
      return *this;
    }
  }

  Book& b;
  Patron& p
  Date d;

};

This might work with your computer, with your compiler, with a specific optimization setting. Then again, it might not. Or it might suddenly stop working when your operator system auto-updates the C++ ABI library. Or it might suddenly stop working when you deliver it to your customer who has a slightly different version of the C++ ABI library.

No matter how you cut it, changing a reference is undefined behavior.

David Hammen
  • 32,454
  • 9
  • 60
  • 108