unable to throw extension of ostringstream

Hi!

I want to make my own exception class which is capable to accept writing streams into it.

The following code compiles on Linux, but does not on Windows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "stdafx.h"

#include <sstream>
#include <iostream>

using namespace std;

class A : public ostringstream {

public:
    int myMember;

    A() : ostringstream() {
    }

    A(const A& proto) : ostringstream() {
        (*this) << ((ostringstream *)(&proto))->str();
    }

    A& operator=(const A& proto) {
        str("");
        (*this) << ((ostringstream *)(&proto))->str();
        return *this;
    }

};


int main() {
    A a;
    cout << "Hello!" << endl;
    throw a;
}


Visual Studio's 2008 VC compiler gives the following two errors:

Error 1 error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>' C:\Program Files\Microsoft Visual Studio 9.0\VC\include\sstream 451 Test_ostringstream
Error 2 error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>' C:\Program Files\Microsoft Visual Studio 9.0\VC\include\ostream 584 Test_ostringstream

What I am doing wrong?

Thanks.
Last edited on
Why are you using derivation?

(BTW, lines 17 and 22 look really, really suspicious).

You should derive your exception class from std::exception and contain a stringstream.
Then write an operator ostringstream() that returns the stream by reference.
Yes, I know there are workarounds. But I want to understan, why I fail this way?

Lines 17 and 22 are written to have absolutely no doubts that compiler doesn't do anything extra, while fighting with it.
P.S.

Linux g++ compiler eats this code normally, but throws error if no copy contructor and asignment defined in A.

The compiler of this site throws warning in definition of copy constructor: http://codepad.org/XEdg5hPv
What I am doing wrong?


Inheriting from the io-streams is a very tricky thing. You should not try to do it. If you really really REALLY want to do this, grab some advanced C++ textbook and read up about virtual base classes and what you have to do to subclass them.

Basically, your problem is that you do not call some constructors which you would have to call.

But really.. spare you the pain and just don't do it! ;-)


Ciao, Imi.

PS: I'd say multiple inheritence among virtual base classes are the most complicated feature in C++... ;-).
I'll second (third?) what others have said, plus add a couple of my own.

A. Exceptions should generally be derived from one of the standard exceptions.
B. Subclassing std iostreams is not trivial.
C. You can just throw a std::stringstream.
D. If you really want to create your own stream class, use the Boost Iostreams libraray.


Thank you guys for your answers but I still do not understand if it is my error or compiler's

imi,

> read up about virtual base classes

what class is virtual here: http://www.cplusplus.com/reference/iostream/
?

> you do not call some constructors which you would have to call

can you explicitly name them?

PanGalactic,

> C. You can just throw a std::stringstream.

of course I can't; this is what I have started from


Oh -- right... Streambufs are non-copyable.
> Streambufs are non-copyable.

So what? My class IS copyable, but I can't throw it. Hence copyableness does not matter.
This compiles and runs with VC2010 and g++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <sstream>
#include <iostream>

using namespace std;

class A : public ostringstream {

public:
    int myMember;

    A() : ostringstream() {}

    A(const A& proto) : ostringstream(proto.str()) {}

    A& operator=(const A& proto) {
        this->str(proto.str());
        return *this;
    }
};


int main(int, char**) {
    try {
        A a;
        a << "Hello!";
        throw a;
    } catch (A& ex) {
        std::cerr << ex.str() << std::endl;
    }
    return 0;
}




what class is virtual here: http://www.cplusplus.com/reference/iostream/?

ios is inherited from both, istream and ostream. iostream uses multiple inheritance to inherit istream and ostream. Hence, iostream would inherit all member variables of ios twice.

To not inherit those members twice, it uses virtual inheritance. For this to work, special requirements when calling constructors apply. E.g. under certain conditions, all further child classes have to call constructors from the virtual base class directly (even if they are not directly subclassed from this class).

The iostream hierarchy itself is not copyable, means they declare their copy constructor private (and never define it). So my guess was, that for your problem the compiler tries to call a constructor of one virtual base class involved which was declared private.

I don't have a firm grasp of multiple virtual inheritance in C++, but I know that this stuff is the biggest reason why a lot of people shun multiple inheritance alltogether. It is one of the most unintuitive and hardest part of C++ and also a part where I would not be surprised at all if I see non-complaince of compilers today.


Anyway, I should not have been so sure about the virtual inheritance thingie in my last post. I made research, and it seems it's not about the multiple inheritance. Looks like VC is completely foobar when it comes to copying exception variables. Or maybe there are some strange definitions about this in the standard. This gives a link error about a missing NoCopy(const NoCopy&) for me!!1!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct NoCopy { 
	NoCopy(){}
	~NoCopy(){}
private:
	NoCopy(const NoCopy&);
};
struct Copy : NoCopy {
	Copy(){}
	Copy(const Copy&):NoCopy(){}
};
int main() {
    throw Copy();
    return 0;
}



PanGalactic wrote:
This compiles and runs with VC2010 and g++:

It doesn't compile in my VS2010. That's my compiler version:


c:\Program Files\Microsoft Visual Studio 10.0\VC\bin>cl /?
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30128.01 for 80x86 Copyright (C) Microsoft Corporation.  All rights reserved.


Maybe I just have to update... ;-)


Ciao, Imi.
Last edited on
Topic archived. No new replies allowed.