Operating System - HP-UX
1834869 Members
2533 Online
110070 Solutions
New Discussion

aC++ conversion operators and/or destructors not working correctly.

 
SOLVED
Go to solution
Andrew Stein
New Member

aC++ conversion operators and/or destructors not working correctly.

I am having a sever problem which I have narrowed down to either conversion operators, and/or destructors and/or object slicing on aCC or RogueWave's implementation of std::string.

The expected output of the attached program is:
zero = zero
zero = zero, one = one
We are getting:
zero = zero
zero = one, one = one

In other words, the std::string zero is being overwritten with the contents of std::string one.

This program was compiled with:
aCC -o main.o -AA -g -c main.cpp
aCC -o main -AA main.o

aCC -V gives:
aCC: HP ANSI C++ B3910B A.03.70

uname -srvm gives:
HP-UX B.11.23 U 9000/800

The contents of main.cpp follow.

Any help would be appreciated.

Thanks,

Andrew
----------------------------------------------
#include
#include

class S : public std::string
{
public:
explicit S(const char* s)
: std::string(s)
{
}
};

class N
{
public:
explicit N(int n)
: _n(n)
{}
operator S() const
{
return _n == 0 ? S("zero") : (_n == 1 ? S("one") : S("other"));
}
private:
int _n;
};

const N& get(int);

int main(int, char**)
{
std::string zero = get(0);
std::cout << "zero = " << zero << std::endl;
std::string one = get(1);
std::cout << "zero = " << zero
<< ", one = " << one << std::endl;

return 0;
}

const N& get(int i)
{
static N ns[2] = {0, 1};
return ns[i];
}

5 REPLIES 5
Andrew Stein
New Member

Re: aC++ conversion operators and/or destructors not working correctly.

By the way, the above code works fine with g++ 3.3 (except for the explicit construction of N from int).
Dennis Handly
Acclaimed Contributor
Solution

Re: aC++ conversion operators and/or destructors not working correctly.

Your code is illegal and violates 12.3.1(2):
static N ns[2] = {0, 1};

You must remove the "explict" on the N constructor or use a cast in the {}.

After fixing this, aCC6 works the way you want. aCC3 gives the wrong answer.

It appears the problem is that a copy constructor is called to copy from the S base class to a temp. Then a bitwise copy from that temp to your zero. This gets the reference counts messed up.

Please contact the Response Center and file a bug report.

Workarounds include:
1) making string a member of S, not a base class.
2) adding an explicit cast to string:
std::string zero = static_cast<:string>(get(0));
Dennis Handly
Acclaimed Contributor

Re: aC++ conversion operators and/or destructors not working correctly.

Better yet, you should not be using "=":
std::string zero(get(0));
Andrew Stein
New Member

Re: aC++ conversion operators and/or destructors not working correctly.

Dennis,

Thanks very much for your replies.

Firstly, you are correct that the explicit N's are a problem, but that this is a side issue. "static N ns = {N(0), N(1)};" is correct and the problem remains.


To the real problem: Of course, what I have is a minimal representation of a problem found porting a 200,000 line body of code to HP-UX/aCC. The S and N classes are part of the platform we use, so they cannot be changed. And buried in our 200,000 lines are literally thousands of statements similar to "std::string xxx = funcReturningAnN(....)".

With this in mind, allow me to relate to each of your suggestions.
(0) moving from aCC 3.70 to aCC 6.xx. From what I understand aCC 6.xx is not available on PA-RISC machines. Is this correct?
(1) making string a member of S. Beyond my control.
(2) adding a explicit cast and (3) using copy rather than assign. These I can do, the problem I have is finding all the places in the code where this occurs. There is no compiler warning just weird run-time errors sometimes, but not every-time. There is also the issue of developers working on other platforms creating more and more of these as we move forward.

So overall, I understand from what you say that I do not have a good solution at all to this problem. Is there any way you can think of that I can at least discover all the places I need to change with (2) or (3) automatically?

Thanks again,

Andrew

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Postscript: I can complain that (2) and (3) should not make any difference at all. By this I mean that the C++ standard says that construction with = should not call the assign operator, but the copy constructor and casting with an explicit cast to do the same as the implicit class should not make a difference either. In other words all of the following should do exactly the same thing:
A a = b;
A a(b);
A a = static_cast(b);
aCC 3.xx is the first compiler that I have seen in many years that does not do this. At least this is fixed in aCC 6.xx


Dennis Handly
Acclaimed Contributor

Re: aC++ conversion operators and/or destructors not working correctly.

It looks like you got CR JAGag34941 filed.

>you are correct that the explicit Ns are a problem, but that this is a side issue.

I said that but I wanted to point out that I can't test things if they have source errors.

>(0) moving from aCC 3.70 to aCC 6.xx. From what I understand aCC 6.xx is not available on PA-RISC machines. Is this correct?

Yes.

>(2) adding a explicit cast and (3) using copy rather than assign.

This isn't an assignment. It is copy initialization, 8.5(12).

>Is there any way you can think of that I can at least discover all the places I need to change with (2) or (3) automatically?

Well, compile with +d and -S and look at the assembly output. If it is only the class S and N, and if it is always function returning N that is converted to S, you could look for N::operator S() followed by a std::basic_string copy constructor, the bad code, then a basic_string destructor then the destructor for S.

Better yet, add the following operator to S:
#ifdef FLAG
private:
operator std::string() const;
#endif

This should flag every use with an error:
error #2330-D: "N::operator std::string() const" is inaccessible
std::string zero = get(0);
^
error #2330-D: "N::operator std::string() const" is inaccessible
std::string one = get(1);
^

(Unfortunately this error doesn't occur on aCC3. You'll have to compile with g++ or aCC6 to see these.) aCC3 will give unsats for that operator and you could again look at the assembly.


>Postscript: I can complain that (2) and (3) should not make any difference at all. By this I mean that the C++ standard says that construction with = should not call the assign operator

The Standard says they are very different.
One is copy initialization, the other is direct initialization. (I didn't say copy assignment operator.)

>but the copy constructor and casting with an explicit cast to do the same as the implicit class should not make a difference either.

It's called a bug. ;-)

>In other words all of the following should do exactly the same thing:
A a = b;
A a(b);
A a = static_cast(b);

No, they don't have to. The ones with "=" don't have to be the same as the (b) case. It depends on the set of rules under 8.5(14). In your case (b is a function call) an extra temp is allowed.

>At least this is fixed in aCC 6.xx

More accurately, it was never broken. ;-)