Re: std::string name4 = name4;
Lynn McGuire <lmc@winsim.com>, on 06/08/2010 15:02:35, wrote:
std::string name4 = name4;
Shouldn't this line of code generate a compiler error ?
It does not in Visual Studio 2005.
With MinGW 4.4.0 the code above has generated a runtime exception from
basic_string - but I guess it has been a coincidence, because it doesn't
happen always. Using that instance afterwards seems more likely to raise
an exception.
This is a topic that turned up really lately also on clc++m, this was my
follow-up there:
http://groups.google.it/group/comp.lang.c++.moderated/msg/fdd504812933771c
Unfortunately nobody replied to me, there, but I think I've come to
understand - more or less - what this issue is all about, and I'm happy
this topic was raised here because I'd like to have my conclusions
reviewed by the group.
If I got it straight, a direct or indirect self-reference in the
construction statement is fine in the following cases:
case A: the involved type is a fundamental type AND the instance has
static lifetime (the instance will always be zero-initialized as first step)
case B: the involved type is not a fundamental type AND
case B1: the self reference does NOT involve access to the uninitialized
data members where these members are part of the type invariant
case B2: the self reference involves access to the uninitialized data
members where these members are NOT part of the type invariant
case C: the involved type is a POD type AND the instance has static
lifetime (all the members will always be zero-initialized as first step)
Breaking any of those rules should lead to undefined behaviour.
[this post advances /no claim/ about being rigorous or complete, the
list of cases above can surely be extended and refined, it seems to me
that case C could be merged to case A or be a special case of case B]
Some examples following and breaking the mentioned cases:
//-------
#include <iostream>
#include <string>
using namespace std;
struct Self {
int data;
Self() : data(0) {
cout << "Self()" << endl;
}
Self(const Self& s) : data(s.data) {
cout << "Self(const Self&)" << endl;
}
Self(int data) : data(data) {
cout << "Self(int)" << endl;
}
};
template<class T> T* new_if_null(T* ptr) {
if (!ptr) {
cout << "ptr is null, initializing ptr" << endl;
ptr = new T;
*ptr = 42;
} else {
cout << "ptr is not null!" << endl;
}
return ptr;
}
// case A
int* global_p_int = new_if_null(global_p_int);
// prints "ptr is null, initializing ptr"
// case A
string* global_p_string = new_if_null(global_p_string);
// prints "ptr is null, initializing ptr"
int main() {
cout << "*global_p_int == " << *global_p_int << endl;
// prints 42
cout << "*global_p_string == " << *global_p_string << endl;
// prints *
// (at least on my system, where '*' == 42)
// case A
static char* static_p_char = new_if_null(static_p_char);
// prints "ptr is null, initializing ptr"
cout << "*static_p_char == " << *static_p_char << endl;
// prints *
// (at least on my system, where '*' == 42)
// case B2
Self b = b;
// prints Self(const Self&)
cout << "b.data == " << b.data << endl;
// prints some junk data
// case B2
Self c = c.data;
// prints Self(int)
cout << "c.data == " << c.data << endl;
// prints some other junk data
// case C
static Self static_b = static_b;
// prints Self(const Self&)
cout << "static_b.data == " << static_b.data << endl;
// prints 0
// case C
static Self static_c = static_c.data;
// prints Self(int)
cout << "static_c.data == " << static_c.data << endl;
// prints 0
// ====================================================
cout << endl << "UB cases: " << endl;
cout << "calling new_if_null(local_p_int):" << endl;
// breaks case A
int* local_p_int = new_if_null(local_p_int);
// prints "ptr is not null!"
cout << "local_p_int == " << local_p_int << endl;
// prints a junk address
cout << "*local_p_int == " << *local_p_int << endl;
// UB, could lead to memory access error or whatever
// breaks case B1
string s = s;
// called string(const string&)
// internal data is junk just like for "Self b(b);"
cout << s << endl;
// UB, s data members contain junk
// and will break std::string invariant
// could lead to some std::basic_string exception
}
//-------
--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com