EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Fwd: Re: Standard String]
From: Marty Kraimer <[email protected]>
To: [email protected]
Date: Mon, 18 Jul 2005 06:47:24 -0500


-------- Original Message --------
Subject: Re: Standard String
Date: Fri, 15 Jul 2005 15:26:00 -0500
From: Andrew Johnson <[email protected]>
Organization: APS, Argonne National Laboratory
To: Marty Kraimer <[email protected]>
CC: Jeff Hill <[email protected]>
References: <[email protected]>



Marty Kraimer wrote:

This is an attempt to see if we can have a standard string implemention.

Jeff said that he wanted it to be an interface class.

Let's look at that idea, without worrying about what it actually looks like: Assume we have all agreed on a single API for a string class that I'll call 'StringInterface,' which is a pure interface class.

I can't instantiate an object of type StringInterface since it's a pure interface class, so in order to create and use a string in my code I would have to define a pointer to a StringInterface, and call a factory routine or use some other means to create a concrete object of my chosen derived class.

    StringInterface *pstring = StringFactory(...);

However because I'm using a pointer, I must remember to release that object (assume for now that just means deleting it) after I've finished with it in order to avoid leaking memory when my pstring goes out of scope:

    delete pstring;

Since I'm a well-educated C++ programmer who understands the RAII idiom (Resource Acquisition Is Initialization), I know how to solve the potential memory leak issue: wrap the pointer inside another class which has a destructor that will delete the string for me.

I could use the standard C++ auto_ptr template to wrap and manage a StringInterface pointer, but I don't want the destructive assignment behaviour that it would give me.

I decide to create a new class implementing StringInterface that contains and manages a StringInterface pointer for me. It will release the object automatically in its destructor, so no memory leaks. That class will look something like this:

class SafeString public StringInterface {
private: // Data
    StringInterface *psi;
public: // Methods
    SafeString(StringInterface *concrete = 0) :
        psi(concrete) {}
    ~SafeString()
    {
        if (psi) delete psi;
    }
    SetStringInterface(StringInterface *concrete)
    {
        if (psi) delete psi;
        psi = concrete;
    }
    // For every method in StringInterface, define
    returnType method(...)
    {
        if (!psi) throw(something...);
        psi->method(...);
    }
private: // Not implemented:
    SafeString(const SafeString& rhs);
    SafeString& operator=(const SafeString& rhs);
};

I can now create an instance of a SafeString and know that I can't leak memory by forgetting to delete the pointer:

    SafeString greeting(StringFactory(...));

SafeString isn't a pure interface class since it contains data, but the only behaviour it actually defines for itself is the ability to manage that pointer for me. I haven't sacrificed any flexibilty on the part of the underlying implementation of StringInterface since I forward all the StringInterface methods to the real implementation, I have just made it safer to use the StringInterface API.

I'd like to make my SafeString slightly easier to use in a couple of very common cases:

1. Suppose there's an implementation of StringInterface available through the StringFactory that takes a C++ 'const char *' literal and makes it accessible using the StringInterface methods. I decide to add a constructor to my SafeString class that explicitly creates one of those kinds of strings when given a 'const char *':

    SafeString(const char *pstr) :
        psi(StringFactory(..., pstr)) {}

I can now write code like this:

    SafeString greeting("Hello, world!");

which is the same as writing this:

    SafeString greeting = "Hello, world!";


2. I can't assign anything to a SafeString at the moment. I declared the self-assignment operator private in the class definition above in order to prevent the compiler from creating one for me that would have just copied the psi pointer, which is definitely the wrong thing to do. Assuming that StringInterface can manipulate a mutable string it must provide some way to copy one string to another. I'll change my class to add an assigment operator using that method:

    SafeString& operator=(const StringInterface& rhs)
    {
        if (!psi) throw(something...);
        // Assuming StringInterface::assign(const StringInterface &)
        psi->assign(rhs);
    }

This now means I can write this:

    SafeString greeting = "Hello";
    SafeString reply = StringFactory(...); // something mutable
    reply = greeting;

Note that there's no copy constructor for SafeString, so I definitely can't write this:

   SafeString greeting = "Hello";
   SafeString reply = greeting; // Link error, not implemented

The copy constructor for reply would have no way to tell what kind of string I want it to instantiate. If StringInterface provided a clone() method I could implement a copy constructor to clone the StringInterface object that it's copying, but if it doesn't then the above code will always have to give a link error. For the purposes of the current argument I don't really care about that, but it's something to bear in mind.


Ok, so I've now defined a class that implements and uses our agreed StringInterface API. It's exactly the same size as a StringInterface pointer, but my class is safe from memory leaks and is more friendly to users. Which should we encourage EPICS V4 users to develop with - StringInterface pointers, or my SafeString class?

Now please compare SafeString to the overall shape of the definition of EpicsString as found in the Wiki page "V4 Design: epicsTypes" at
http://www.aps.anl.gov/epics/wiki/index.php/V4_Design:_epicsTypes#epicsString


I would be happy to discuss changes to (or even a complete replacement for) the EpicsBuffer interface which EpicsString was based on, and changes to the methods of EpicsString itself. We can talk about whether an EpicsString IS an EpicsBuffer, HAS an EpicsBuffer or even IS-IMPLEMENTED-IN-TERMS-OF an EpicsBuffer (EffC++), but I will not accept a standard string class which is just a pure virtual interface. I hope the above discussion shows why.


Jeff, I'll be commenting on your reply in a separate message.

- Andrew

PS: Why aren't we discussing this on core-talk?
--
Podiabombastic: The tendency to shoot oneself in the foot.



Navigate by Date:
Prev: [Fwd: RE: Standard String] Marty Kraimer
Next: [Fwd: Re: Standard String] Marty Kraimer
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: RE: [Fwd: RE: Standard String] Jeff Hill
Next: [Fwd: Re: Standard String] Marty Kraimer
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·