tags:

views:

390

answers:

5

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.

+4  A: 

I think you should look into the possibility of using boost::shared_ptr (or std::tr1::shared_ptr).

Anders Abel
This is a pass by value data type. I think your suggestion is valid for a pass by reference data type.
Gokul
His suggestion is good for a copyable, pass-by-value class. A non-copyable pass-by-reference type has no copying issues, obviously.
John Kugelman
I meant to use shared_ptr for tracking the std::string* and deallocating on the right moment. How will your code handle a case where an Atom containing an std::string has been copied several times and the original instance has the longest lifetime?
Anders Abel
I need only to make sure that the data will get deleted, when there are no references.
Gokul
@Andres:: Will that condition occur when i have a pass by value data type?? Usually it will be passed from one function to another and copied via assignment.
Gokul
+3  A: 

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?

sbi
Yes, i looked at boost::any. It cannot be used here, because we need serialization of this.
Gokul
@Gokul: It's not as if your type would come with serialization for free - you'd have to implement that yourself as well. If you base yours on `boost:any`, at least you've got a solid foundation.
sbi
+1  A: 

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.

Michael Burr
yes, i will have only that constructor and no set-statements.
Gokul
@Gokul - that's not really the issue. Can you be certain that whoever invokes the constructor will do so only with a string that's been allocated via `new` and that the caller won't subsequently call `delete` on the string? These are rules that would be difficult to enforce with your design, so it might be a good idea to think about them before committing to such a design.
Michael Burr
@Michael: Sorry, i didn't mention about it, but people will only pass it on as std::string and i will convert it into std::string* inside this. So i need to free it. If it is passed as std::string*, then this won't worry about freeing it.
Gokul
+2  A: 

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.)

StackedCrooked
Thanks!! i will check it out.
Gokul
Stranger, please explain when you're downvoting :)
StackedCrooked
+4  A: 

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.

John Kugelman
Thanks.. I got the issue. But i am unable to use boost::any because it doesn't support boost serialization
Gokul
You can add serialization to your class (as you are surely doing now) and use internally either boost::any or boost::variant
David Rodríguez - dribeas
@David: I don't want to pay the cost of boost::any, if i can't store the type_info( by converting everything into void* and then putting it inside boost::any ). Currently i am serializing by taking the data as stream of bytes, with the length.
Gokul
How do you know how you must interpret the deserialized element? What is the cost you cannot pay with teh boost::any approach (memory, serialized information)?
David Rodríguez - dribeas
@David: boost::any has virtual function call for every data extraction, for every copy constructor call, for every destructor call and it involves dynamic allocation for even the simple data types
Gokul