Making a std::string a member of a union ???

S

Simon G Best

Peter said:
I am creating my own computer language and I need a simple way to store the
various elemental data types.

Sounds like you probably want runtime polymorphism, if I'm guessing
right. That means deriving from base classes, having virtual functions,
and that sort of thing. Much better than unions :)
 
P

Peter Olcott

Simon G Best said:
Peter said:
When I am saying that it is entirely free of semantics, I mean at the
programming level, not at the human communication level. In other words the
above statement has no corresponding machine code that is generated from the
compilation process. It translates into nothing at all.

This is just wrong.

Consider the following:-

[Start C++ snippet.]

#include <iostream>

class something {
public:
something() { std::clog << "Oh, look!" << std::endl; }
};

class Simple {
something a;
public:
Simple() {}
};

So it looks like you are saying that Simple() invokes something() therefore
simple does something and I am wrong that Simple(){} is empty of semantics.
void foo() { Simple x; }

[End C++ snippet.]

What happens when you call foo()?

Also consider the case where Simple::Simple() is declared in a header, for
inclusion in multiple translation units, but defined elsewhere.
 
P

Peter Olcott

Gianni Mariani said:
boost::any (or somthing similar) should do what you want. They do all the
copy/destruct work that unions don't and you need for std::string.

I wrote a similar beast at::Any. You can get it from:
http://netcabletv.org/public_releases/

(warning - it's big, it contains a number of precompiled libs)

If all that I want is std::string could I simply use [ std::string* String ] in
my union?
 
R

Ron Natalie

Peter said:
Okay since the official standard specifically refers to non trivial
constructors, try and provide an example of a non trivial constructor that is
more trivial than:
ClassName(){};
Trivial has a specific definition. I already posted what it is. It is
completely in contradiction with your snippet above.
 
R

Ron Natalie

Peter said:
If all that I want is std::string could I simply use [ std::string* String ] in
my union?

You would need management code to allocate and deallocate it.
 
P

Peter Olcott

Simon G Best said:
Sounds like you probably want runtime polymorphism, if I'm guessing right.
That means deriving from base classes, having virtual functions, and that sort
of thing. Much better than unions :)

I don't think that it is a good fit for runtime polymorphism because I will have
datatypes with disjoint sets of operations, such as std::string and double.
runtime polymorphism is the best fit when the sets of operations are identical,
yet their specific implementation varies. This is not one of those cases.
 
P

Peter Olcott

Ron Natalie said:
Trivial has a specific definition. I already posted what it is. It is
completely in contradiction with your snippet above.

Yeah, Simon proved that I was wrong.
 
P

Peter Olcott

Ron Natalie said:
Peter said:
If all that I want is std::string could I simply use [ std::string* String ]
in my union?

You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
 
R

Ron Natalie

Peter said:
Ron Natalie said:
Peter said:
If all that I want is std::string could I simply use [ std::string* String ]
in my union?
You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
You need to remember which element you stored in the vector.

Once you do all that you probably have reimplemented boost::any.
 
S

Simon G Best

Peter said:
Okay since the official standard specifically refers to non trivial
constructors, try and provide an example of a non trivial constructor that is
more trivial than:
ClassName(){};

The standard actually defines what it means by "non-trivial
constructor". And another respondent has already summarised it.

Anyway:-

[Start C++ snippet.]

#include <iostream>
#include <string>

class base {
public:
base() { std::clog << "Looky here!" << std::endl;
};

class foo : public base {
std::string s;
public:
foo() {} // This is non-trivial.
};

class bar {
std::string s;
public:
bar() {} // This is non-trivial, too.
};

[End C++ snippet.]

Neither foo::foo() nor bar::bar() are trivial. Both construct s
(implicitly), but only foo::foo() constructs base as well. We /could/
then say that bar::bar() is closer to being trivial than foo::foo().
 
S

Simon G Best

Peter said:
So it looks like you are saying that Simple() invokes something() therefore
simple does something and I am wrong that Simple(){} is empty of semantics.

Yep :)
 
B

BobR

Peter Olcott wrote in message said:
If I create my own StringType class that has every other feature of std::string,
except nontrivial constructors, then it should work?
For example if every instance of StringType is always empty unless data is
explicitly added using operator=() or other means, then there would seem to be
no need for constructors.

Storage? What good is a String class that can't store anything?

Do you understand what a union is?

std::cout<<" sizeof(std::string) ="
<<sizeof(std::string)<<std::endl;
std::cout<<" sizeof(double) ="
<<sizeof(double)<<std::endl;
// out: sizeof(std::string) =4
// out: sizeof(double) =8

So, if you did (if it compiled):

union AnyType {
std::string String;
double Number;
};

.... the union would be the size of a double (since it is bigger than
std::string (on my machine)).

Try it this way:

#include <iostream> // #include <ostream>
#include <string>

union AnyType {
std::string *String; // pointer
double Number;
};

int main(){
AnyType AnyT;
std::string Sting("AnyType AnyT;");
AnyT.String = &Sting;
std::cout<<" AnyT.String ="<<*(AnyT.String)<<std::endl;
AnyT.Number = 543.123;
std::cout<<" AnyT.Number ="<<AnyT.Number<<std::endl;
// oops! // std::cout<<" AnyT.String ="<<*(AnyT.String)<<std::endl;
return 0;
} // main()

But, the union still doesn't seem logical to me.
 
P

Peter Olcott

Ron Natalie said:
Peter said:
Ron Natalie said:
Peter Olcott wrote:

If all that I want is std::string could I simply use [ std::string*
String ] in my union?
You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
You need to remember which element you stored in the vector.

Once you do all that you probably have reimplemented boost::any.

Okay then this is the way that I will do it.
 
M

Michael DOUBEZ

Peter Olcott a écrit :
Is there anyway of doing this besides making my own string from scratch?

union AnyType {
std::string String;
double Number;
};

Use pointer instead.
union AnyType
{
std::string* str;
double number;
};
And don't forget to delete it before writing into the
structure(embedding that in a structure with accessor).

Or use boost::variant or boost::any as Thomas J. Gritzan wrote.

Michael
 
P

Peter Olcott

Michael DOUBEZ said:
Peter Olcott a écrit :

Use pointer instead.
union AnyType
{
std::string* str;
double number;
};

And don't forget to delete it before writing into the structure(embedding that
in a structure with accessor).

I don't know what you mean by this.
 
J

Jim Langston

Peter Olcott said:
Ron Natalie said:
Peter said:
Peter Olcott wrote:

If all that I want is std::string could I simply use [ std::string*
String ] in my union?
You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
You need to remember which element you stored in the vector.

Once you do all that you probably have reimplemented boost::any.

Okay then this is the way that I will do it.

It depends on what you are actually tryign to do. A union of a double and a
pointer doesn't seem like it will do you any good. It sounds more like you
want to refer to this double as either a double, or as a std::string,
correct? It would seem a simple class would work for you. Something like:

#include <iostream>
#include <string>
#include <sstream>

class AnyType
{
public:
operator double() const { return Val_; }
operator std::string () const
{
std::stringstream Convert;
Convert << Val_;
return Convert.str();
}
AnyType* operator= ( const double Val ) { Val_ = Val; return this; }
AnyType* operator= ( const std::string& Val )
{
std::stringstream Convert;
Convert << Val;
Convert >> Val_;
return this;
}
private:
double Val_;
};

int main()
{
AnyType MyDouble;
MyDouble = 1234.56;
std::cout << MyDouble << "\n";
MyDouble = "2345.67";
std::cout << MyDouble << "\n";

std::string wait;
std::getline( std::cin, wait );
}

This could easily be converted to a template for any type.

Is this the kind of thing you are looking for?
 
M

Michael DOUBEZ

Peter Olcott a écrit :
I don't know what you mean by this.

I dont pretend it is good C++ design but it looks like what you ask for.

Accessor solution is something like this (not tested):
struct GenericContent
{
public:
//! supported types
enum mytype{ type_none, type_str, type_number };

//constructor - destructor
GenericContent():_type(type_none){}
~GenericContent()
{ //clean internal data
this->clean_me();
}
//! setters
void setString(const std::string& str)
{ //clean internal data
this->clean_me();
this->_type=type_str;
this->_data.str=new std::string(str);
}
void setNumber(double num)
{ //clean internal data
this->clean_me();
this->_type=type_number;
this->_data.number=num;
}

//! accessors
mytype getType()const
{
return this->_type;
}
const string& getString()const
{
assert(this->_type==type_str);
return *(this->_data.str);
}
double getNumber()const
{
assert(this->_type==type_number);
return this->_data.number;
}
private:
//! clean internal data and reset to none
void clean_me()
{
if(this->_type==type_str)
{
delete this->_data.str;
}
this->_type=type_none;
}

//! refuse copy ...
GenericContent(const GenericContent&);
GenericContent& operator=(const GenericContent& genc);

private:
//! store real content of data
mytype _type;
//! data
union
{
std::string* str;
double number;
} _data;
};
 
P

Peter Olcott

I can't tell what you are trying to do here, but, the std::string will probably
not hold data that can be converted to and from string.

Jim Langston said:
Peter Olcott said:
Ron Natalie said:
Peter Olcott wrote:
Peter Olcott wrote:

If all that I want is std::string could I simply use [ std::string*
String ] in my union?
You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
You need to remember which element you stored in the vector.

Once you do all that you probably have reimplemented boost::any.

Okay then this is the way that I will do it.

It depends on what you are actually tryign to do. A union of a double and a
pointer doesn't seem like it will do you any good. It sounds more like you
want to refer to this double as either a double, or as a std::string, correct?
It would seem a simple class would work for you. Something like:

#include <iostream>
#include <string>
#include <sstream>

class AnyType
{
public:
operator double() const { return Val_; }
operator std::string () const
{
std::stringstream Convert;
Convert << Val_;
return Convert.str();
}
AnyType* operator= ( const double Val ) { Val_ = Val; return this; }
AnyType* operator= ( const std::string& Val )
{
std::stringstream Convert;
Convert << Val;
Convert >> Val_;
return this;
}
private:
double Val_;
};

int main()
{
AnyType MyDouble;
MyDouble = 1234.56;
std::cout << MyDouble << "\n";
MyDouble = "2345.67";
std::cout << MyDouble << "\n";

std::string wait;
std::getline( std::cin, wait );
}

This could easily be converted to a template for any type.

Is this the kind of thing you are looking for?
 
S

Sylvester Hesp

Peter Olcott said:
Is there anyway of doing this besides making my own string from scratch?

union AnyType {
std::string String;
double Number;
};

If you really want to union the memory footprint of types with non-trivial
constructors, you could wrap them in a container which has a trivial
constructor. Unfortunately, this will currently not yield very portable code
as you won't have any control over alignment, but it will probably work on
most platforms:

#include <string>

template<class T> class UnionMember
{
public:
void construct()
{ new (*this) T(); }
template<class P1> void construct (const P1 & p1)
{ new (*this) T(p1); }
template<class P1, class P2> void construct (const P1 & p1, const P2 &
p2)
{ new (*this) T(p1, p2); }
// etc.

void destroy() { (*this)->~T(); }

operator T * () { return reinterpret_cast<T*>(m_data); }
operator const T * () const { return reinterpret_cast<const
T*>(m_data); }

T * operator -> () { return operator T*(); }
const T * operator -> () const { return operator const T*(); }

private:
char m_data[sizeof(T)]; // for true portable code you'll need to align
this buffer to meet the alignment requirements for T.
};

union MyUnion
{
UnionMember<std::string> myString;
double myDouble;
};

int main()
{
MyUnion u;

// construct a string within the union
u.myString.construct("hi there");

// assign it with a different string
*u.myString = "goodbye";

// assign the double - don't forget to destroy the string first!
u.myString.destroy(); // destroy the string
u.myDouble = 34.5; // and assign the double.
}

You should take care to construct every object on it's first use and
destruct it before using another value in the union, or when you dispose of
the union.

The next C++ standard revision will most probably include methods of
retrieving and controlling alignment of datamembers.

- Sylvester
 
J

Jim Langston

Jim Langston said:
Peter Olcott said:
Peter Olcott wrote:
Peter Olcott wrote:

If all that I want is std::string could I simply use [ std::string*
String ] in my union?
You would need management code to allocate and deallocate it.

I already figured that, are there any other issues?
You need to remember which element you stored in the vector.

Once you do all that you probably have reimplemented boost::any.

Okay then this is the way that I will do it.

It depends on what you are actually tryign to do. A union of a double
and a pointer doesn't seem like it will do you any good. It sounds more
like you want to refer to this double as either a double, or as a
std::string, correct? It would seem a simple class would work for you.
Something like:

#include <iostream>
#include <string>
#include <sstream>

class AnyType
{
public:
operator double() const { return Val_; }
operator std::string () const
{
std::stringstream Convert;
Convert << Val_;
return Convert.str();
}
AnyType* operator= ( const double Val ) { Val_ = Val; return this; }
AnyType* operator= ( const std::string& Val )
{
std::stringstream Convert;
Convert << Val;
Convert >> Val_;
return this;
}
private:
double Val_;
};

int main()
{
AnyType MyDouble;
MyDouble = 1234.56;
std::cout << MyDouble << "\n";
MyDouble = "2345.67";
std::cout << MyDouble << "\n";

std::string wait;
std::getline( std::cin, wait );
}

This could easily be converted to a template for any type.

Is this the kind of thing you are looking for?

Peter Olcott said:
I can't tell what you are trying to do here, but, the std::string will
probably not hold data that can be converted to and from string.

Please don't top post. Message rearranged.

You mean not hold data that can be converted to and from a double?

Okay, so you want your union to hold *either* a std::string or a double.
There are a few ways to do this including templates, templates with common
base class, pointers, etc...

How is it you want to be able to use AnyType?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top