First off: I searched half the web to find an answer with this as a solution that came closest. It is, however, too heavyweight for me though so I am looking a little less complex.
Well then, some context: I am building a system which should be able to process incoming messages from a queue and then store the outcome of these messages in another queue. I would like to store these responses in a generic class because I am storing it in a multimap.
The response class currently is defined as follows
class COutboundMsg
{
public:
enum eTypeHint {
thNone,
thSomeType,
thLast
};
eTypeHint m_TypeHint;
void* m_OutboundData;
COutboundMsg(COutboundMsg::eTypeHint TypeHint, void* data);
};
COutboundMsg::COutboundMsg(COutboundMsg::eTypeHint TypeHint, void* data) :
m_TypeHint(TypeHint),
m_OutboundData(data)
{
}
Now, the current way of working would involve a user to do something like this:
CSomeType* data = new CSomeType();
COutboundMsg(COutboundMsg::thSomeType , (void*) data);
It would be up to the user at the other end to cast the void* back to CSomeType* (using the type hint) and delete it.
It don't like it.
I'd rather have the m_OutboundData contained in an auto_ptr or something and make sure that it deletes itself when done.
Any ideas? Maybe a different approach altogether
Normally polymorphism is used for a system like this; any item that can be put in the Outbound queue derives from QueueItem and the queue contains QueueItem* or a smart pointer to a QueueItem.
Since the items all derive from a common base, you can safely delete the QueueItem* or allow a smart pointer to handle it. This approach also allows you to use dynamic_cast to make sure that the pointer is, in fact, pointing to an object of the type you think it is.
If this approach is possible, be sure to make the QueueItem destructor virtual, otherwise the derived class's destructor won't be called.
shared_ptr stores a deleter to use to delete the object, and so does not depend on the static type of the pointer at the time of deletion. So something like this should do the right thing:
COutboundMsg(eTypeHint TypeHint, shared_ptr<void> msg);
shared_ptr<CSomeType> data(new CSomeType);
COutboundMsg(COutboundMsg::thSomeType, data);
If the set of messages is known before hand (transmit/receive), rather than polymorphism, consider a variant type, I'm taking specifically about boost::variant<>.
The advantage of this approach is that each message is a specific type (I know it seems like you don't want to implement this - however as a long term design feature, I think you'll find this approach extensible) and the variant describes the set of messages, let me show a quick example:
let's say I have two messages
struct Logon{};
struct Logout{};
I define a variant to hold the possible set of messages, at a given time it's only ever one of them..
typedef boost::variant<Logon, Logout> message_type;
Now I can store this in any container, and pass it around like normal, the only difference is that the truly generic way to access them is via visitors, e.g.
struct process : boost::static_visitor<>
{
void operator()(Logon const& cLogon)
{
// do stuff
}
void operator()(Logout const& cLogout)
{
// do stuff
}
};
// method that processes a given message
void processMessage(message_type const& cMsg)
{
// don't know what this message is, that's fine, hand it to the visitor
boost::apply_visitor(process(), cMsg); // the correct overload will be called for the message
}
...I think it's slightly better than void* ;)
Related
I have a map of that maps string ids to a specific implementation of base_object.
Any base_object has a method get_id that returns the id of the object.
and I fill up the map using (pseudo)
void addToMap(base_object* obj){
make_pair(obj->get_id(),obj);
}
This map acts like a factory, and knows to return the correct object using the id. this is the method declaration for retrieving specific object:
base_object* get(string id);
All the objects do not have fields only a polymorphic method that behaves differently for each implementation.
I am not sure what is the best way to implement this.
Should the map be a map of <string,unique_ptr<base_object>>
In this case when I am returning a base_object using get, is it ok to return a raw pointer to base_object? (I know that the map will keep living so that the object will not get destroyed?)
or maybe in this case I should use a shared_ptr?
Also, since the object doesn't really have any fields, maybe it is better to return a copy of the object?
Any way I look at this it looks to me like a bad design, and I just can't decide what is the best approach to solve this.
I am very new to cpp so I am not very familiar with all the differences and best usages of pointers...
Use unique_ptr<base_object> const &. That signals to the caller that what it gets is a handle on a unique object having the id that it requested. Using a shared_ptr signals that it may be responsible for keeping the object alive.
Also, there's no need for a map: you can use a set or unordered_set that orders/hashes based on the id. That way, you won't have to store the id twice.
(The thing you're implementing is more of an object pool than a factory.)
You can use std::unique_ptr<base_object> and return a const reference to the unique_ptr.
Possible implementation:
struct Data
{
std::map<std::string,std::unique_ptr<base_object>> data;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
const std::unique_ptr<base_object>& get(const std::string& id) {
return data.at(id);
}
};
Use case example:
Data data;
data.add(new test1_object{});
data["test1"]->create(); // call a virtual function of base_object
Note, that this is not really a factory. If the abstract function of base_object should be responsible for creating your actual product, you can perhaps do this:
struct Factory
{
std::map<std::string,std::unique_ptr<base_object>> workers;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
Product create(const std::string& id) {
return data.at(id)->foo(); // call the virtual function here
}
};
Factory factory;
factory.add(new test1_object{});
Product x = factory.create("test1");
The standard of the factory pattern is not filled up with objects on start. There are no objects at all. The factory only knows how to create a new object. A possible implementation can do this with a map and registered static! methods of the class ( not a object ).
And a factory should always return a new instance and not a reference or a pointer to an already existent object. The application typically have no idea how to destroy this special kind of copies instead of own instances.
How you best design your thing depends on the use-cases and design constraints:
If you can guarantee the returned object lives long enough and you can guarantee you'll return an actual object, returning by reference is best (if not having an object to return, there are exceptions. Use where appropriate).
If you can guarantee the returned object lives long enough if there is an object to return, just return by raw pointer.
If all of the maps elements should live to the end of the program, do not make the map own them unless it lives as long and you want to force it to clean them up: Allocate them statically or dynamically (in the second case you might want to register them with std::atexitfor cleanup at the end), and let the map only hold an un-owning raw pointer.
If your program will not be compiled without RTTI and every object is a singleton of its class, consider using typeid for the key (at least the name field) instead of a custom string.
Anyway, you later say the only interesting point of those objects is one single method: Why don't you just use std::function for maximum flexibility?
A std::unordered_map has amortised O(1) access, a std::map only O(ln(n)).
So, I've done (a small amount) of reading and am aware that unique_ptr in combination with raw pointers is the pattern to use when modeling unique ownership.
However, I really like the simple and clear concept of using a weak_ptr to check if a value is valid, and then discard the shared_ptr after using it, and this keeps everyone happy (at a slight reference counting performance cost).
My particular problem right now is in creating an expressive and flexible system for tracking multitouch points, and it seemed elegant to use the destruction of the object that represents a touch to be the signal that the touch has ended. If I went with the raw pointer route, I would need to define some semantics that each component interfacing with this system would need to conform to, something slightly ugly like having a second argument involved that indicates whether the pointer is valid or some such.
This issue with the raw pointer route is perhaps a strawman issue as I don't expect this to become a large project, but the question is mostly of practical interest in terms of how to write the best modern C++ code.
pseudocode:
class InputConsumer {
void handle(std::list<std::weak_ptr<Touch>>*);
// consumer doesnt hold references to anything outside of its concern.
// It only has to know how to deal with input data made available to it.
// the consumer is a child who is given toys to play with and I am trying to
// see how far I can go to sandbox it
}
class InputSender {
std::list<std::weak_ptr<Touch>> exposedinputdata;
std::list<std::shared_ptr<Touch>> therealownedtouches;
// sender populates exposedinputdata when input events come in.
// I want to let the consumer copy out weak_ptrs as much as it wants,
// but for it to never hold on to it indefinitely. There does not appear
// to be an easy way to enforce this (admittedly it is kind of vague. it
// has to be around for long enough to be used to read out data, but
// not e.g. 3 frames. Maybe what I need is to make an intelligent
// smart pointer that has a timer inside of it.)
std::list<std::weak_ptr<InputConsumer>> consumers;
void feedConsumersWithInput() {
for (auto i = consumers.begin(); i != consumers.end(); ++i) {
if (i->expired()) {
consumers.erase(i);
} else {
i->lock()->handle(&exposedinputdata);
}
}
}
When I saw the ability of weak_ptr to express very similar semantics to what I am modeling, I just really wanted to use it, because its interface is clean and simple, and most importantly it self-documents how this code is going to work. This is a huge benefit down the road.
Now I'm pretty sure that everything will be really peachy until such time as an InputConsumer calls lock() on weak_ptr<Touch> and retains the shared_ptr<Touch>. It will prevent the underlying Touch from being freed even after the primary owner of it has erased its owning shared_ptr! This seems to me the only wrinkle, and a little one at that. I think it's far harder to screw up ownership handling with shared_ptr than it is to do so with raw pointers.
What are some ways of patching this up? I am thinking of maybe making a template subclass (?! I have never written such a thing, recently got into templates. Loving them) of weak_ptr that will somehow forbid retaining a shared_ptr, or something.
Maybe I can subclass shared_ptr and override its dtor to throw if it doesn't call the deleter?
Considering that having a weak_ptr always requires reference counting, rolling out whatever solution is (more or less) like rewriting the shared_ptr one.
The quick and dirty way is probably derive shared_ptr and provide it with only the move ctor (monitore_ptr(monitored_ptr&&) ) and transfer operator (monitored_ptr& operator=(monitored_ptr&&) ), thus disabling the shared_ptr copy (and hence "sharing") capabilities.
The problem of derivation is that, being shared_ptr not polymorphic, you end up with a non polymorphic type that exibit some polymorphism towards shared_ptr (you can assign to it, thus violating your assumptions).
This can be compensated by using protected inheritance and re-expose only the required functionalities (essentially the * and -> operators).
To avoid miss-behavior against weak_ptr (like your monitored_ptr given to weak_ptr given to shared_ptr)... I'll also suggest to override weak_ptr as well, with protected inheritance.
At that point you end up with a pair of classes that are self sufficient and not compatible with any other shared pointer.
In any case, the key is writing proper contructors, and not (as you proposed) throw in the destructor: it is a situation with a lot of potential gotcha, hardly manageable.
(see for example here)
I'm going to propose a pretty simple design. It is a thin wrapper around a weak_ptr where the only way to access the underlying T is to pass a lambda to a method.
This restricts the lifetime of the shared_ptr from lock() to be the time you call the method: while in theory you can lock the shared_ptr indefinitely, you can only do it by never returning from the try.
template<typename T>
struct monitored_pointer {
template<typename Lambda>
bool try( Lambda&& closure ) const {
auto p = m_ptr.lock();
if (!p)
return false;
std::forward<Lambda>(closure)(*p):
return true;
}
bool valid() const {
return try( [](T&){} );
}
void reset( std::weak_ptr<T> ptr = std::weak_ptr<T>() )
{
m_ptr = ptr;
}
explicit operator bool() const { return valid(); }
monitored_pointer() {}
monitored_pointer( monitored_pointer && ) = default;
monitored_pointer& operator=( monitored_pointer && ) = default;
explicit monitored_pointer( std::weak_ptr<T> ptr ):m_ptr(ptr) {}
private:
std::weak_ptr<T> m_ptr;
};
valid and operator bool just helps when you want to clean out expired monitored_pointers.
Use looks something like:
if (!ptr.try( [&]( Touch& touch ) {
// code that uses the `touch` here
})) {
// code that handles the fact that ptr is no longer valid here
}
I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".
i have a "data provider" which stores its output in a struct
of a certain type, for instance
struct DATA_TYPE1{
std::string data_string;
};
then this struct has to be casted into a general datatype,
i thought about void * or char *, because the "intermediate"
object that copies and stores it in its binary tree should
be able to store many different types of such struct data.
struct BINARY_TREE_ENTRY{
void * DATA;
struct BINARY_TREE_ENTRY * next;
};
this void * is then later taken by another object
that casts the void * back into the (struct DATA_TYPE1 *)
to get the original data. so the sender and the receiver
know about the datatype DATA_TYPE1 but not the copying
object inbetween.
but how can the intermidiate object deep copy the contents of
the different structs, when it doesn't know the datatype,
only void * and it has no method to copy the real contents;
dynamic_cast doesn't work for void *;
the "intermediate" object should do something like:
void store_data(void * CASTED_DATA_STRUCT){
void * DATA_COPY = create_a_deepcopy_of(CASTED_DATA_STRUCT);
push_into_bintree(DATA_COPY);
}
a simple solution would be that the sending object doesn't
delete the sent data struct, til the receiving object got it,
but the sending objects are dynamically created and deleted,
before the receiver got the data from the intermediate object,
for asynchronous communication, therefore i want to copy
it.
instead of converting it to void * i also tried converting
to a superclass pointer of which the intermediate copying
object knows about, and which is inherited by all the different
datatypes of the structs:
struct DATA_BASE_OBJECT{
public:
DATA_BASE_OBJECT(){}
DATA_BASE_OBJECT(DATA_BASE_OBJECT * old_ptr){
std::cout << "this should be automatically overridden!" << std::endl;
}
virtual ~DATA_BASE_OBJECT(){}
};
struct DATA_TYPE1 : public DATA_BASE_OBJECT {
public:
string str;
DATA_TYPE1(){}
~DATA_TYPE1(){}
DATA_TYPE1(DATA_TYPE1 * old_ptr){
str = old_ptr->str;
}
};
and the corresponding binary tree entry would then be:
struct BINARY_TREE_ENTRY{
struct DATA_BASE_OBJECT * DATA;
struct BINARY_TREE_ENTRY * next;
};
and to then copy the unknown datatype, i tried in the class
that just gets the unknown datatype as a struct DATA_BASE_OBJECT *
(before it was the void *):
void * copy_data(DATA_BASE_OBJECT * data_that_i_get_in_the_sub_struct){
struct DATA_BASE_OBJECT * copy_sub = new DATA_BASE_OBJECT(data_that_i_get_in_the_sub_struct);
push_into_bintree(copy_sub);
}
i then added a copy constructor to the DATA_BASE_OBJECT, but if
the struct DATA_TYPE1 is first casted to a DATA_BASE_OBJECT and then
copied, the included sub object DATA_TYPE1 is not also copied.
i then thought what about finding out the size of the actual object
to copy and then just memcopy it, but the bytes are not stored in
one row and how do i find out the real size in memory of the
struct DATA_TYPE1 which holds a std::string?
Which other c++ methods are available to deepcopy an unknown datatype
(and to maybe get the datatype information somehow else during
runtime)?
If you have a void * there is no way of extracting any type information from it. That is why void * are very, very rarely used in C++ programs (I honestly cannot remember the last time I used one) - your approach here is completely mistaken. If you want generic containers where the type is known at compile time, use templates. If you want containers where the type varies at run-time, derive from a base class and use containers of base class pointers. And don't write your own containers (except possibly as learning exercises ) - C++ has a perfectly good binary tree implemented as std::set and std::map.
And lastly, don't use ALL CAPS for names of C++ types.
Void pointers are not a good solution here because they do not guarantee type-safety at compiletime.
I suggest using templates. This will allow you to still deal with different datatypes using the same class/functions, and will also guarantee typesafety much better than void pointers.
Edit: To further clarify why void pointers even exist: void pointers were used for this kind of thing in C. However while you can still use them in C++, it is usually discouraged because there are better solutions.
Also, you mention deepcopying. All types to be used with the database should either have to implement deepCopy function (this is an OOP-style approach), or you could simply remember to overload the assignment operator for all types you use with your DATA_BASE :)
but how can the intermidiate object deep copy the contents of the different structs, when it doesn't know the datatype, only void * and it has no method to copy the real contents; dynamic_cast doesn't work for void *;
You simply can't do that. A void* block representing certain data is bound to contain multiple pointers (std::string allocates memory dynamically, for example). And you won't know where exactly they are stored, so there will be no way to deep copy data without causing a mess somewhere.
dynamic_cast doesn't work for void *;
You could try to cast void* into some base type, then dynamic_cast into whatever you want. However, I can't guarantee that it will be safe to use that with object created by multiple inheritance, for example. It will be safer to use some abstract class for exchanging data, instead of void* pointers.
Which other c++ methods are available to deepcopy an unknown datatype (and to maybe get the datatype information somehow else during runtime)
What you're looking at here is serialization: The ability to place various objects in a binary stream, move the stream around - and maybe store it, then get a copy of the original contents back out of the stream.
You can implement this yourself, or you can base your implementation on existing libraries.
One option I have used is boost::serialization. You basically have to implement either a serialize method in all your class hierarchy, or a save and a load method in all your class hierarchy.
The code is pretty straightforward. See here for the tutorial.
thanks for the quick answers.
i'm somehow too lazy to rewrite the code in the future each time
in every class when a new datatype is added.
for me now i could do it with templates for each datatype that is used,
but i really wonder from a code development point of view if there
isn't a simpler thing in c++. you are right that i come from c and
i will slowly behave myself when programming in c++.
i tried this approach with inheritance of a base class, which
is already a restriction for coding, because every new datatype
has to be coded to inherite the base struct, but this doesn't work,
because only calling the copy contructor of the base struct, which is
the only thing the "copy-object" knows (because it doesn't know anything
about the derived struct datetypes), can do, doesn't work.
the copy contructor of the derived struct is not called, or am i doing
something wrong here? i tried it with the assignment operator, but
it doesn't do a copy and as soon as the original data is deleted,
it is a dangling pointer i guess.
At the moment it works like this
the "sending object" creates a struct DATA_TYPE1 * with new DATA_TYPE1 ...
and fills it with data
and casts it to void *
and tells the "copy-object" about this pointer
then the "sending object" is deleted, the contents of the void * is still alive
the "copy-object" stores just the void *
the "receiving object" gets this void * at a later time
and casts it back to the struct DATA_TYPE1 * and uses its data
and finally deletes the data
so no copying is done here just handing over the pointer to
the original data from one object to the other.
thanks for the advice about serialisation i thought about that,
but at the moment i want to turture myself with pure c++ to
solve this problem.
I have a universal data type, which is passed by value, but does not maintain the type information. We store only pointers and basic data types(like int, float etc) inside this. Now for the first time, we need to store std::string inside this. So we decided to convert it into std::string* and store it. Then comes the problem of destruction. We don't like to copy the std::string every time. So i am thinking of an approach like this. Say the data type looks like this
class Atom
{
public :
enum flags
{
IS_STRING,
IS_EMPTY,
HAS_GOT_COPIED,
MARKER
};
private:
void* m_value;
std::bitset<MARKER> m_flags;
public:
.....
Atom( Atom& atm )
{
atm.m_flags.set( HAS_GOT_COPIED );
.....
}
.....
~Atom()
{
if( m_flags.test(IS_STRING) && !m_flags.test(HAS_GOT_COPIED) )
{
std::string* val = static_cast<std::string*>(m_value);
delete val;
}
}
};
Is this a good approach to find out whether there is no more reference to std::string*? Any comments..
I have looked at boost::any and poco::DynamicAny. Since i need serialization, i can't use those.
Thanks,
Gokul.
One major flaw with this approach is that you really need a reference count, not a single bit "has been copied" flag. The bit won't work if you copy the string multiple times. As written, you will get into trouble if you create a copy of an Atom and delete the copy before the original:
Atom a("hello world");
if (...) {
Atom b(a);
// b is destroyed, deleting the string
}
// Uh oh, the string's been deleted but a is still referencing it.
cout << (string) a;
I would not re-invent the wheel. If boost::any doesn't work out of the box you could still use it internally in place of your m_value field to store the data for your Atom class. That would take care of all the construction/copying/destruction details for you.
I think you should look into the possibility of using boost::shared_ptr (or std::tr1::shared_ptr).
You might want to feed "copy on write" into google and read up on the topic. How it is usually implemented, what it is used for, and what its drawbacks are.
And have you looked at boost::any?
One of my first tasks at my first job was to design a variant class. You can find some basic code (and discussion) here in this comp.lang.c++.moderated post.
Since you also need serialization, you might be interested in the JsonCpp library. I think it offers just what you are looking for: a datatype that can be a string, bool, int, array, object, etc... (the Json::Value class.)
Aside from whether this kind of 'universal data type' is a good idea, if you're not copying the string, can this class be sure that it owns the string it has pointer to? Can you guarantee that only strings allocated via new will be passed in to the class to take ownership?
The design of this class looks as though it will be problematic.