Topic: Library functions invalidating references (was Is this a defect?)


Author: Alexandre Mah <alexm@cse.unsw.EDU.AU>
Date: Mon, 4 Feb 2002 18:57:46 GMT
Raw View
On Sat, 2 Feb 2002, Ratiba&Karima wrote:

> I really don'y know whats your problem.

The problem wasn't so clearly stated in my second post, and I think I
might have caused some confusion with my second post because my point of
view changed between my first and second posts.  Sorry about that.

Here is an elucidation and expansion of the problem:

The vector member functions push_back() and insert() both can take a
reference as an argument.  The question was "Are push_back() and insert()
required by the C++ standard to properly handle the case when the
reference is a reference to an element in the vector itself?"

After carefully reading through the details in the C++ standard, I
determined that the answer to the question was a decisive "yes,
definitely!".  (This happened between my first and second posts.)

This means that the STL libraries in Microsoft Visual C++ 6.0 and probably
many other STL implementations are not conformant to the standard on this
point.  (IBM VisualAge 4.0 and GCC however are conformant.)

For some concrete examples, suppose you have:
vector<someType> v;
Then "v.push_back(v.front())" and even "v.insert(v.begin(), v[3])"
(provided v contains more than 3 elements) are required by the C++
standard to be handled properly.

Microsoft Visual C++ 6.0 cannot properly handle
"v.insert(v.begin(), v[3])".

The problem is caused by the fact that v[3] is passed to insert as a
reference and the value that is referenced is changed by insert itself.
The C++ standard requires that the value that is inserted into the
sequence container is the value that is passed into the function, not the
value that insert() eventually puts into v[3].

GCC and IBM VisualAge C++ 4.0 both conform to the standard with respect to
the behaviour of insert(), but they do so by copying the value to be
inserted.

This brings us to another peculiarity.
If conformant compilers are going to do this, what is the point of passing
in the value by reference if it is just going to be copied?  Why doesn't
insert(iterator, reference) just take its second argument by value rather
than by reference (since passing by value is more efficient than passing
by reference and having insert copy the value straight away)?

If you want to test out the conformance of your compiler, try out the
following code.
If the program is compiled by a standard-conformant compiler, then the
value 3 should be in v[0] at the end of the program.
Microsoft Visual C++ 6.0 incorrectly has 2 in v[0] at the end of the
program.

///////////////////////////////////////////////////
#include <iostream>
#include <vector>

using namespace std;

struct s {
    int x;
    s(const s& k) { x = k.x; cout << "Copy Constructing " << x << endl; }
    s(int i) { x = i; cout << "Conversion " << x << endl; }
    s &operator=(const s& k) {
        x = k.x;
        cout << "Assigning " << x << endl;
        return *this;
    }
    ~s() { cout << "Destructing " << x << endl; }
};

int main(void) {
    vector<s> v;
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);
    cout << v.capacity() << endl;
    v.insert(v.begin(), v[3]);
    cout << v.capacity() << endl;
    for (int i = 0; i < v.size(); i++)
        cout << i << ' ' << v[i].x << endl;
    return 0;
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]