RAII mit boost::shared_ptr und boost::bind   December 12th, 2010

In meinem heutigen Post möchte ich euch etwas erzählen über den shared_ptr und seine Fähigkeit allozierte Ressourcen abweichend von delete mit einer benutzerdefinierten Funktion oder einer benutzerdefinierten Methode zu entfernen. Nehmen wir einmal an, wir hätten eine Klasse, welche Speicher verwaltet und auf Anfrage Handles auf Speicher herausgibt und über die vergebenen Handles den Speicher wieder löscht. Um Speicherlöcher zu finden zählt die Klasse den vergebenen und wieder beseitigten Speicher mit. Eine solche Klasse könnte wie folgt aussehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "stdafx.h"
#include <assert.h>
#include <boost\shared_ptr.hpp>
#include <boost\function.hpp>
#include <boost\bind.hpp>
#include <iostream>
 
typedef unsigned char MemChunk;
typedef unsigned char* MemHandle;
 
class MemResourceFabric
{
private:
  MemResourceFabric():count_(0){}
public:
  static MemResourceFabric* instance(){static MemResourceFabric i;return &i;}
  ~MemResourceFabric()
  {
    assert(count_==0);
  }
  MemHandle openMemory()
  {
    count_++;
    return new unsigned char[100];
  }
  void closeMemory(MemHandle mem_handle)
  {
    count_--;
    delete [] mem_handle;
  }
private:
  int count_;
};

Über die Funktion openMemory() wird der Speicher angefordert, über die Funktion closeMemory(MemHandle mem_handle) wieder freigegeben. Wenn nun innerhalb einer Funktion eine Ausnahme auftritt, könnte es sein, dass der angeforderter Speicher nicht mehr freigegeben wird, da unter C++ die Funktion closeMemory nicht von selber aufgerufen wird. Hier kann uns das unter C++ sehr weit verbreitete Idiom RAII (Resource Alocation Is [Resource] Initialization) mithilfe von boost::shared_ptr und boost::bind helfen. Normalerweise gibt der shared_ptr verwaltete Ressourcen in seinen Destruktor per delete wieder frei. Man kann ihm aber auch einen Funktor übergeben, welcher die verwaltete Resource anstelle von delete wieder freigeben soll. Im vorliegenden Beispiel soll der angeforderter Speicher mithilfe der Funktion closeMemory wieder freigegeben werden. Als Instanz soll unser Singleton, MemResourceFabric verwendet werden:

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int _tmain(int argc, _TCHAR* argv[])
{
  boost::shared_ptr<MemChunk> shp_mem_1(
    MemResourceFabric::instance()->openMemory(),
    boost::bind(
      &MemResourceFabric::closeMemory,
      MemResourceFabric::instance(),
      _1)
  );
 
  strcpy(
    (char*)shp_mem_1.get(),
    "Hello memory. Memory wird auch bei Ausnahmen deleted.");
 
  std::cout << (char*)shp_mem_1.get() << std::endl;
 
  return 0;
}

Diese Technik ist in einer Reihe von Szenarios sehr hilfreich, bei denen die Ressourcen abseits von delete verwaltet werden: Datenbank öffnen, Netzwerkverbindung öffnen, Datei öffnen, Synchronisation von Threads, et cetera…

Viel Spaß mit RAII und bis zum nächsten Post,

Daniel.

Tags: , , , , ,
This entry was posted on Sunday, December 12th, 2010 at 01:45 and is filed under C++ (and more...). You can follow any responses to this entry through the RSS 2.0 feed.You can leave a response, or trackback from your own site.

No Responses

Leave a Reply