Persistant Properties With C++ - the Readable Way

.

Environment: VC6

Introduction

During my many years of C++ programming I ran into so many cases where there was a collection of persistant properties to be maintained by means of system registry, INI files, database tables etc. etc., and as a fanatic for clear and readable code I always hated to see how my code get cluttered each time I wanted to set a new property or query for a previously saved one.

When STL first came out it was fascinating to see how easy it was to set a new value in a map container and query for it later on, just by using the [] operator. I mean, if I could only do things like:

CDatabaseTable dbt("my_table");
dbt["Name"] = "Joe Shmoe";
cout << dbt["Name"] << endl;

...or...

CRegistry r(HKEY_CURRENT_USER, "Software\\MyApp\\Settings");
r["window_x"] = 112;
r["window_y"] = 200;

After all, if you leave alone the read and write that fit each storage nature, this is all very much the same thing, wouldn't you agree ?

To make the long story short, I needed the means to work with any dictionary-like storage by using the [] operator for both read and write. Nothing too fancy, I agree, but certainly a life saver for a readable-code freak like myself!

So Here It Is...

template <class Key, class Value>
class CPropertiesStorage
{
public :
  class CPropertiesStoragePair
  {
  public :
    Key first;
    Value second;

    CPropertiesStoragePair(CPropertiesStorage& stg)
      : m_storage(stg) {}
    CPropertiesStoragePair(CPropertiesStorage& stg, 
                           const Key& k)
      : m_storage(stg), first(k) {}
    CPropertiesStoragePair(CPropertiesStorage& stg, 
                           const Key& k, 
                           const Value& v)
      : m_storage(stg), first(k), second(v) {}
    CPropertiesStoragePair(const CPropertiesStoragePair& sp)
      : m_storage(sp.m_storage), first(sp.first), 
              second(sp.second) {}

    CPropertiesStoragePair& operator = (const Value& v)
    {
      second = v;
      m_storage.Write(first, second);
      return *this;
    }

    CPropertiesStoragePair& operator = 
               (const CPropertiesStoragePair& sp) const
    {
      if( &sp != this )
      {
        m_storage = sp.m_storage;
        first = sp.first;
        second = sp.second;
      }
      return *this;
    }

    operator const Value&() const
    {
      return (const Value&)second;
    }

  private :
    CPropertiesStorage& m_storage;
  };
  friend class CPropertiesStoragePair;

  CPropertiesStorage() {}
  virtual ~CPropertiesStorage() {}

  CPropertiesStoragePair operator[] (const Key& k)
  {
    CPropertiesStoragePair sp(*this, k);
    Read(sp.first, sp.second);
    return sp;
  }

protected :
  virtual void Read(const Key& k, Value& v) = 0;
  virtual void Write(const Key& k, const Value& v) = 0;
};

There are two template parameters, the key type and the value type. This is just like what you should already know from your STL experience. The only thing that is left is two pure-virual methods where you can implement the actual read and write mechanism according to the storage you're using. I've also decided not to return any result form those two functions because at that stage I can't be totally sure of how you might implement those two methods. I figured that the actual implementation would throw some kind of exception it something bad happens.

Sample

Here is a sample code that uses an INI file as the storage media:

class CIniFileSection 
    : public CPropertiesStorage<std::string, std::string>
{
public :
  CIniFileSection(const char* lpszIniFileName, 
                  const char* lpszSection)
    : m_sIniFileName(lpszIniFileName), 
                     m_sSection(lpszSection)
  {
  }

protected :
  const std::string m_sIniFileName;
  const std::string m_sSection;

  virtual void Read(const std::string& k, std::string& v)
  {
    char szBuf[200];
    GetPrivateProfileString(m_sSection.c_str(), 
                            k.c_str(), 
                            "", 
                            szBuf, sizeof(szBuf), 
                            m_sIniFileName.c_str());
    v = szBuf;
  }

  virtual void Write(const std::string& k, 
                     const std::string& v)
  {
    WritePrivateProfileString(m_sSection.c_str(), 
                              k.c_str(), 
                              v.c_str(), 
                              m_sIniFileName.c_str());
  }
};

int main()
{
  CIniFileSection r("d:\\test.ini", "main");

  r["key1"] = "value1";

  std::cout << r["key1"].second << std::endl;

  return 0;
}

Finally...

What I'm presenting here is an idea. If any of you have a better way to do what I have tried to do, please let me know.



Comments

  • reviews after squander clarisonic mia 2

    Posted by iouwanzi on 06/06/2013 04:26pm

    [url=http://www.miaclarisonicaustralia.org/clarisonic-classic]clarisonic classic[/url] peut-être mieux si vous profitez de cette fondation se bloque style pour le monde moderne. devenir une personne mystifié destinée à une bonne approche très bon pour faire la coiffure impressionnante? vous permet de le fait que c’est dans la terre soigneusement introduire une règle peut être limitée par un excellent instrument qui est connecté n’est pas vraiment efficace appréciation des résultats définitifs de ces cheveux crépus? et peut également demander le jaune est toujours dans vos propres besoins redressement de vos cheveux. Rose tout simplement charmant, le moment, en raison de la longue durée développer la gestion motif merveilleux et très important. En outre, ghd lisseur en céramique infrarouge critique couvre belle chevelure bouclée, et également la compression d’huiles naturelles, de l’eau et de serrures colorants alimentaires, bouclés cheveux sauvages éclatantes assurés reçoivent des produits de qualité supérieure qui va venir. [url=http://www.australiaclarisonic.com/]clarisonic australia[/url] Avec concernant la saison de Noël, j’ai couru à travers une idée de cadeau vraiment attractif, votre package de Collection de nuit. un nouvel ensemble de boîte très exquis option limitée en place qui comprend également tous les flambant neuf G Platinum intemporelle GHD Styler haute définition, matériel résistant à la chaleur, seulement deux caractéristiques montre les cheveux bouclés, un nouveau miroir de belle main baroque, un séchoir de cheveux bouclés nouvelles d’acquérir voyage autour ultra-compact, ainsi qu’une belle organisation. [url=http://www.miaclarisonicaustralia.org/]clarisonic mia 2[/url] Je voudrais que celui qui crée mon vos cheveux aspect extraordinaire, ainsi que que j’ai pu utilisation pour vous aider à redresser et faire de superbes boucles. C’est pour quelle raison mon conjoint et j’ai décidé de commander quelques autre ghd Gold styler.Qu’ils sont sérieusement incroyables, avec, on dirait qu’ils soient uniquement en conséquence substantielle dans un an ou deux, sauf si la rend plue ramasser la fonction ! Qu’ils sont dignes du plus abordable par opposition à travers Aus, ainsi que leur prix, très dernière longtemps. ghd Gold styler ont un instrument d’authentification très bon sur les sites Web pour vous assurer que vous avez une totale fiabilité fer plat.

    Reply
  • Great, but...

    Posted by Legacy on 09/09/2003 12:00am

    Originally posted by: Patr�cia Nunes

    It doesn't work for Windows CE environment...

    Some suggestion?

    TIA

    Reply
  • Could be more generic

    Posted by Legacy on 05/28/2002 12:00am

    Originally posted by: Shannon G Barber

    Since you're making a template class, you could (dare I say should!) use a policy template parameter to provide read & write functors. This technique is used extensively in the Boost library and in Loki (i.e. it's an established and recongized method)

    It's the generic approach rather than the OO approach you have constructed. Does the storage media need to change during run-time? Odds are good you'll always want the same storage for a given operation, so you can skip the OO overhead and use functors.

    Also, the read/write concepts ought to return a value (bool is a good choice - true success, false failure), then you do not /require/ an exception to be thrown to indicate failure, unlike the example implementation.

    Actually, you could even leave the return value nebulous and not specific it for the read/write concept, and then each policy could return an appropriate type!

    Reply
  • Useful and to the point

    Posted by Legacy on 12/01/2001 12:00am

    Originally posted by: Giora Katz-Lichtenstein

    This is the right way a code section should be provided. It adds value, it is clear and it does the job.

    Giora

    Reply
  • stl include?

    Posted by Legacy on 08/31/2001 12:00am

    Originally posted by: Edgar Tu

    Hi,

    I've never done STL programming before, but your class facinates me. I'm using VC++ 6 and trying to compile your sample. I'm getting errors on "string is not a member of std". Can someone help me out?

    thx,
    edgar

    Reply
  • And what about default values?

    Posted by Legacy on 08/16/2001 12:00am

    Originally posted by: Dmitriy Sholomov

    Hi!
    
    

    Your idea is right, but as for me, there are two lacks in the implementation.

    1) GetPrivateProfileString function has lpDefault parameter. In the implementation of your classes you don't use it. In the situation when INI file contains SomeKey= (the value="") you'll get the same value as if there is no record in the INI file. I suggest to add
    const Value CPropertiesStorage::operator() (const Key& k, const Value& v_def) to the CPropertiesStorage class.

    2) When you use ini_file_section["key"]=val; construction to write data you also read data from INI file in the operator []. Is it necessary?

    Bye!

    Reply
  • Minor detail

    Posted by Legacy on 08/14/2001 12:00am

    Originally posted by: Martijn Dashorst

    First I would like to say that this is a great class... I already used it! There is however a small detail which should be changed:

    The operator CPropertiesStorage::CPropertiesStoragePair::operator=(const CPropertiesStoragePair&) const shouldn't be const:

    CPropertiesStorage::CPropertiesStoragePair::operator=(const CPropertiesStoragePair&)
    is the correct definition.

    Reply
  • Brilliant Idea

    Posted by Legacy on 08/10/2001 12:00am

    Originally posted by: Robert Liu

    A Great Idea! Could be roll out as a util Lib

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds