/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Klasse til automatisk frigivelse af resurs~
Fra : Byrial Jensen


Dato : 03-10-03 20:20

Hej gruppe

Jeg har et problem med et C++-program som bruger et C-bibliotek.
Biblioteket ser i princippet sådan her ud:

$ cat lib.h
// lib.h
// Dette skal forestille et "eksternt" bibliotek
#ifndef _LIB_H_
#define _LIB_H_
#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
int a;
int b;
} LIB_CTX;

LIB_CTX *lib_make_ctx (void);
void lib_free_ctx (LIB_CTX *ctx);
int lib_ctx_set_a (LIB_CTX *ctx, int a); // Return non-zero for error
int lib_ctx_set_b (LIB_CTX *ctx, int b); // Return non-zero for error
void lib_use_ctx (LIB_CTX *ctx);
#ifdef __cplusplus
}
#endif
#endif // _LIB_H_

$ cat lib.c
// lib.c
// Dette skal forestille et "eksternt" bibliotek
#include "lib.h"
#include <stdlib.h>
#include <stdio.h>

LIB_CTX *lib_make_ctx (void)
{
LIB_CTX *ctx = malloc (sizeof (LIB_CTX));
if (!ctx)
return 0;
ctx->a = 0;
ctx->b = 0;
return ctx;
}

void lib_free_ctx (LIB_CTX *ctx)
{
free (ctx);
}

int lib_ctx_set_a (LIB_CTX *ctx, int a)
{
if (a > 5)
return 1;
ctx->a = a;
return 0;
}

int lib_ctx_set_b (LIB_CTX *ctx, int b)
{
if (b > 7)
return 1;
ctx->b = b;
return 0;
}

void lib_use_ctx (LIB_CTX *ctx)
{
printf ("Use of LIB_CTX %p\n", ctx);
}


Jeg vil gerne undgå at arbejde med pointere til LIB_CTX, så jeg har
lavet en klasse MY_CTX som stærkt inspireret af autoptr gerne skulle
sørge for at kalde lib_free_ctx() når min pointer går ud af scope:

$ cat make_ctx.h
// make_ctx.h
#ifndef _MAKE_CTX_H_
#define _MAKE_CTX_H_

#include "lib.h"

class MY_CTX
{
private:
LIB_CTX *ctx;

public:
MY_CTX (LIB_CTX *c);

MY_CTX (MY_CTX &c);

~MY_CTX ();

MY_CTX & operator = (MY_CTX &c);

operator LIB_CTX * () const;

bool operator ! () const;
};

MY_CTX make_ctx ();

#endif // _MAKE_CTX_H_

$ cat make_ctx.cpp
// make_ctx.cpp
#include "make_ctx.h"
#include <iostream>
using std::cout;
using std::endl;

MY_CTX::MY_CTX (LIB_CTX *c)
{
ctx = c;
cout << "constructor - ctx = " << ctx << endl;
}

MY_CTX::MY_CTX (MY_CTX &c)
{
ctx = c.ctx;
c.ctx = 0;
cout << "copy constructor - ctx = " << ctx << endl;
}

MY_CTX:MY_CTX ()
{
cout << "destructor - ctx = " << ctx << endl;
if (ctx)
lib_free_ctx (ctx);
}

MY_CTX & MY_CTX:erator = (MY_CTX &c)
{
cout << "assignment - ctx = " << ctx << " RHS.ctx = " << c.ctx << endl;
if (this != &c)
{
if (ctx)
lib_free_ctx (ctx);
ctx = c.ctx;
c.ctx = 0;
}
return *this;
}

MY_CTX:erator LIB_CTX * () const
{
cout << "konvertering til LIB_CTX * - ctx = " << ctx << endl;
return ctx;
}

bool MY_CTX:erator ! () const
{
cout << "operator ! - ctx = " << ctx << endl;
return ! ctx;
}

MY_CTX make_ctx ()
{
MY_CTX ctx (lib_make_ctx ());
if (!ctx)
throw "Cannot make ctx";

if (lib_ctx_set_a (ctx, 3))
throw "Cannot set a";

if (lib_ctx_set_b (ctx, 4))
throw "Cannot set b";

return ctx;
}

Endelig har jeg et lille testprogram:

$ cat main.cpp
// main.cpp
#include "make_ctx.h"
int main ()
{
MY_CTX ctx (make_ctx ());
lib_use_ctx (ctx);
return 0;
}

Når programmet køres, sker der følgende:

$ cat Makefile
# Makefile
prog: main.o make_ctx.o lib.o
   g++ -Wall -W main.o make_ctx.o lib.o -o prog
main.o: main.cpp make_ctx.h lib.h
   gcc -Wall -W -c main.cpp -o main.o
make_ctx.o: make_ctx.cpp make_ctx.h lib.h
   gcc -Wall -W -c make_ctx.cpp -o make_ctx.o
lib.o: lib.c lib.h
   gcc -Wall -W -c lib.c -o lib.o

$ make
gcc -Wall -W -c main.cpp -o main.o
gcc -Wall -W -c make_ctx.cpp -o make_ctx.o
gcc -Wall -W -c lib.c -o lib.o
g++ -Wall -W main.o make_ctx.o lib.o -o prog
$ ./prog
constructor - ctx = 0x804a538
operator ! - ctx = 0x804a538
konvertering til LIB_CTX * - ctx = 0x804a538
konvertering til LIB_CTX * - ctx = 0x804a538
konvertering til LIB_CTX * - ctx = 0x804a538
constructor - ctx = 0x804a538
destructor - ctx = 0x804a538
konvertering til LIB_CTX * - ctx = 0x804a538
Use of LIB_CTX 0x804a538
destructor - ctx = 0x804a538


Jeg havde forventet at copy-constructoren for MY_CTX blev brugt når
returværdien skal foreføres fra make_ctx() til main(), men i stedet
konverteres værdien til en LIB_CTX* med det resultat at lib_free_ctx()
kaldes fra make_ctx() med den samme pointer som også gives til main()
med katastrofale konsekvenser til følge.

Hvorfor virker programmet ikke? Og hvordan får jeg det til at virke så
lib_free_ctx() ikke kaldes fra make_ctx() hvis pointeren bliver overført
til main()?

På forhånd tak og mange hilsener
Byrial


 
 
Ivan Johansen (03-10-2003)
Kommentar
Fra : Ivan Johansen


Dato : 03-10-03 22:08

Byrial Jensen wrote:
> Jeg havde forventet at copy-constructoren for MY_CTX blev brugt når
> returværdien skal foreføres fra make_ctx() til main(), men i stedet
> konverteres værdien til en LIB_CTX* med det resultat at lib_free_ctx()
> kaldes fra make_ctx() med den samme pointer som også gives til main()
> med katastrofale konsekvenser til følge.
>
> Hvorfor virker programmet ikke? Og hvordan får jeg det til at virke så
> lib_free_ctx() ikke kaldes fra make_ctx() hvis pointeren bliver overført
> til main()?

Jeg vil give dig ret i at din copy constructor burde blive kaldt, så jeg
vil mene at det er en compiler bug. Dette bekræftes af Borland C++
Builder som giver et program med følgende output:
constructor - ctx = 9132112
operator ! - ctx = 9132112
konvertering til LIB_CTX * - ctx = 9132112
konvertering til LIB_CTX * - ctx = 9132112
copy constructor - ctx = 9132112
destructor - ctx = 0
konvertering til LIB_CTX * - ctx = 9132112
constructor - ctx = 9132112
destructor - ctx = 9132112
konvertering til LIB_CTX * - ctx = 9132112
Use of LIB_CTX 008B5850
destructor - ctx = 9132112

Jeg er meget sikker på at du kan omgå problemet ved at erstatte din
conversion operator med en almindelig funktion i klassen på samme måde
som std::auto_ptr::get(). Conversion operators har det for øvrigt med at
give uforudsigelige problemer.

Ivan Johansen


Peter Kragh (04-10-2003)
Kommentar
Fra : Peter Kragh


Dato : 04-10-03 03:53


"Ivan Johansen" <NG4@padowan.dk> wrote in message >
> Jeg vil give dig ret i at din copy constructor burde blive kaldt, så jeg
> vil mene at det er en compiler bug. Dette bekræftes af Borland C++
> Builder som giver et program med følgende output:

Dette er ikke en compiler bug. Ifølge c++ standarden kap. 12.8 (§15), så
skal copy constructoren ikke nødvendigvis kaldes i f.eks. dette tilfælde:

class foo
{
...
};

foo bar()
{
foo r;
return r;
}

En anden måde at løse problemet på, kunne være at lade sig inspirere af
Visual C++ 6.0's implementation af std::auto_ptr. Du skal så føje en bool
member variabel til din klasse. Denne bool fortæller om MY_CTX instansen
"ejer" ctx'en. Der vil max være en MY_CTX instans, der ejer en given ctx
(lib_free_ctx skal kun kaldes i destruktoren, hvis instansen ejer ctx'en).
Ejerskabet styres vha. constructor, assignment-operatoren og
copy-constructoren.

Håber det hjælper.

Mvh.
Peter Kragh



Peter Kragh (04-10-2003)
Kommentar
Fra : Peter Kragh


Dato : 04-10-03 04:33


"Peter Kragh" <peter.kragh@__remove__this__mensa.dk> wrote in message
news:SKpfb.3107$Kv.62901@news000.worldonline.dk...

> En anden måde at løse problemet på, kunne være at lade sig inspirere af
> Visual C++ 6.0's implementation af std::auto_ptr. Du skal så føje en bool
> member variabel til din klasse. Denne bool fortæller om MY_CTX instansen
> "ejer" ctx'en. Der vil max være en MY_CTX instans, der ejer en given ctx
> (lib_free_ctx skal kun kaldes i destruktoren, hvis instansen ejer ctx'en).
> Ejerskabet styres vha. constructor, assignment-operatoren og
> copy-constructoren.
>

Hhhmmm, rodede lidt videre med det for sjov skyld...

Det virkede kun, hvis copy-constructor'en og assignment-operatoren får
const-referencer (som normalt!) a'la:

MY_CTX (const MY_CTX &c);

og

MY_CTX & operator = (const MY_CTX &c);

, men så kræver det lidt mere, at sætte ejerskabet i RHS objectet til false:

const_cast<MY_CTX*>(&c)->bOwn = false;

Så skulle den være der

Mvh.
Peter Kragh



Byrial Jensen (04-10-2003)
Kommentar
Fra : Byrial Jensen


Dato : 04-10-03 09:37

Peter Kragh wrote:
> "Peter Kragh" <peter.kragh@__remove__this__mensa.dk> wrote
>
>>En anden måde at løse problemet på, kunne være at lade sig inspirere af
>>Visual C++ 6.0's implementation af std::auto_ptr. Du skal så føje en bool
>>member variabel til din klasse. Denne bool fortæller om MY_CTX instansen
>>"ejer" ctx'en. Der vil max være en MY_CTX instans, der ejer en given ctx
>>(lib_free_ctx skal kun kaldes i destruktoren, hvis instansen ejer ctx'en).
>>Ejerskabet styres vha. constructor, assignment-operatoren og
>>copy-constructoren.

Tak for svaret. Jeg er allerede inspireret af std::auto_ptr idet
copy-constructoren og assignment-operatoren sætter ctx i det objekt der
kopieres/tildeles fra, til 0. Men det hjælper jo ikke hvis ikke de
pågældende funktioner bliver brugt.

> Hhhmmm, rodede lidt videre med det for sjov skyld...
>
> Det virkede kun, hvis copy-constructor'en og assignment-operatoren får
> const-referencer (som normalt!) a'la:
>
> MY_CTX (const MY_CTX &c);
>
> og
>
> MY_CTX & operator = (const MY_CTX &c);
>
> , men så kræver det lidt mere, at sætte ejerskabet i RHS objectet til false:
>
> const_cast<MY_CTX*>(&c)->bOwn = false;

Jeg ændrede argumenterne i de 2 funktioner til const referencer, men i
stedet for at lave const_cast erklærede jeg MY_CTX::ctx for "mutable".
(Jeg har det ikke godt med const_cast og var ikke sikker på at brugen
her ville være defineret).

Nu giver mit program følgende udskrift ved kørsel:

$ ./prog
constructor - ctx = 0x804a4c8
operator ! - ctx = 0x804a4c8
konvertering til LIB_CTX * - ctx = 0x804a4c8
konvertering til LIB_CTX * - ctx = 0x804a4c8
konvertering til LIB_CTX * - ctx = 0x804a4c8
Use of LIB_CTX 0x804a4c8
destructor - ctx = 0x804a4c8

Så tilsyneladende virker det, men jeg forstår stadig ikke hvad der sker!
Det ser ud at copy-constructoren slet ikke bliver kaldt, og destructoren
kaldes kun én gang selvom både make_ctx() og main() har lokale MY_CTX
variabler.

Det er formodentlig tilladt at optimere kald af copy-constructor og
destructor væk når en funktion returnerer et lokalt objekt? Det ville
rart om nogen kan kaste lidt lys over hvorfor programmet virker som det
gør, og om copy-constructorer og assignment-operatorer skal have const
referencer.


Jonas Meyer (04-10-2003)
Kommentar
Fra : Jonas Meyer


Dato : 04-10-03 10:28


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:3F7E86C8.4090900@nospam.dk...
> $ ./prog
> constructor - ctx = 0x804a4c8
> operator ! - ctx = 0x804a4c8
> konvertering til LIB_CTX * - ctx = 0x804a4c8
> konvertering til LIB_CTX * - ctx = 0x804a4c8
> konvertering til LIB_CTX * - ctx = 0x804a4c8
> Use of LIB_CTX 0x804a4c8
> destructor - ctx = 0x804a4c8
>
> Så tilsyneladende virker det, men jeg forstår stadig ikke hvad der sker!
> Det ser ud at copy-constructoren slet ikke bliver kaldt, og destructoren
> kaldes kun én gang selvom både make_ctx() og main() har lokale MY_CTX
> variabler.
>
> Det er formodentlig tilladt at optimere kald af copy-constructor og
> destructor væk når en funktion returnerer et lokalt objekt? Det ville
> rart om nogen kan kaste lidt lys over hvorfor programmet virker som det
> gør, og om copy-constructorer og assignment-operatorer skal have const
> referencer.


Problemet er, så vidt jeg kan se, at hvis du skal give en midlertidig
variabel
med til en funktion, som tager en reference, så skal det være en const
reference.
I dit oprindelige eksempel lavede du en midlertidig variabel med din make
funktion,
som der så kunne bruges til din copyconstructor, fordi den tog en ikke const
reference.

Jeg syntes det giver mening at den nægter at give en midlertidig
variabel med som ikke const reference - En ikke const reference
er jo en antydning af at du vil ændre i den, og det giver næppe mening at
ændre i en midlertidig variabel.

mvh Jonas




Mogens Hansen (04-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 04-10-03 11:34


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:3F7E86C8.4090900@nospam.dk...

[8<8<8<]
> Det ville
> rart om nogen kan kaste lidt lys over hvorfor programmet virker som det
> gør, og om copy-constructorer og assignment-operatorer skal have const
> referencer.

Copy-constructor og copy-assignment kan som første argument tage
X&
const X&,
volatile X&
const volatile X&
som parameter.
Det fremgår af §12.8 i C++ Standarden.
Det mest almindelige er dog at de tager "const X&", og det er naturligvis
også den form der kan bruges i flest sammenhænge.


Venlig hilsen

Mogens Hansen



Byrial Jensen (04-10-2003)
Kommentar
Fra : Byrial Jensen


Dato : 04-10-03 09:13

Ivan Johansen wrote:
>
> Jeg vil give dig ret i at din copy constructor burde blive kaldt, så jeg
> vil mene at det er en compiler bug. Dette bekræftes af Borland C++
> Builder som giver et program med følgende output:

Tak for svaret. Men jeg tvivler nu på at mine problemer skyldes fejl i
min oversætter, og anser for mere sandsynligt at de skyldes manglende
evner og/eller viden.

Hvis du kigger nærmere på udskriften fra din kørsel af programmet
nedenfor, vil du se at det også kalder destructoren med det samme ikke-0
argument 2 gange hvilket selvfølgelig ikke må ske:

> constructor - ctx = 9132112
> operator ! - ctx = 9132112
> konvertering til LIB_CTX * - ctx = 9132112
> konvertering til LIB_CTX * - ctx = 9132112
> copy constructor - ctx = 9132112
> destructor - ctx = 0
> konvertering til LIB_CTX * - ctx = 9132112
> constructor - ctx = 9132112
> destructor - ctx = 9132112
> konvertering til LIB_CTX * - ctx = 9132112
> Use of LIB_CTX 008B5850
> destructor - ctx = 9132112
>
> Jeg er meget sikker på at du kan omgå problemet ved at erstatte din
> conversion operator med en almindelig funktion i klassen på samme måde
> som std::auto_ptr::get(). Conversion operators har det for øvrigt med at
> give uforudsigelige problemer.

Måske, men jeg vil gerne forstå hvorfor mit program virker som det gør.


Mogens Hansen (04-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 04-10-03 11:27


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:3F7E8100.6060807@nospam.dk...

[8<8<8<]
> Tak for svaret. Men jeg tvivler nu på at mine problemer skyldes fejl i
> min oversætter,

Det er ikke en fejl i compileren.

> og anser for mere sandsynligt at de skyldes manglende
> evner og/eller viden.

Sådan er det heldigvis for det meste


[8<8<8<]
> Måske, men jeg vil gerne forstå hvorfor mit program virker som det gør.

Er du kommet tættere på en forståelse ud fra forklaringerne om temporære
objekter og const ?

Venlig hilsen

Mogens Hansen



Byrial Jensen (05-10-2003)
Kommentar
Fra : Byrial Jensen


Dato : 05-10-03 08:14

Mogens Hansen wrote:
> "Byrial Jensen" <bjensen@nospam.dk> wrote
>
>>Måske, men jeg vil gerne forstå hvorfor mit program virker som det gør.
>
> Er du kommet tættere på en forståelse ud fra forklaringerne om temporære
> objekter og const ?

Ja, det mener jeg. Tak til dig og de andre svarere som har kastet lys
over sagen.


Mogens Hansen (04-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 04-10-03 11:10


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:3F7DCBE7.5080706@nospam.dk...

[8<8<8<]
> Jeg havde forventet at copy-constructoren for MY_CTX blev brugt når
> returværdien skal foreføres fra make_ctx() til main(), men i stedet
> konverteres værdien til en LIB_CTX* med det resultat at lib_free_ctx()
> kaldes fra make_ctx() med den samme pointer som også gives til main()
> med katastrofale konsekvenser til følge.
>
> Hvorfor virker programmet ikke? Og hvordan får jeg det til at virke så
> lib_free_ctx() ikke kaldes fra make_ctx() hvis pointeren bliver overført
> til main()?

Det korte svar:

make_ctx returnerer et temporært objekt, som er en r-value - altså det kan
ikke modificeres.
Din copy-constructor tager en ikke-const reference til et objekt, og kan
derfor ikke bruges til at lave en kopi med.
Der kigger compileren sig om efter andre muligheder, og finder at den kan
konverteres til en LIB_CTX* via conversion operator som er en const funktion
(bør den iøvrigt være const ?). Fra en LIB_CTX* kan compileren så oprette en
MY_CTX og så er alle glade - lige indtil programmet skal køre og crasher!

Altså lav MY_CTX lidt om:
<C++ code>
class MY_CTX
{
private:
mutable LIB_CTX *ctx;

public:
explicit MY_CTX (LIB_CTX *c);

MY_CTX (const MY_CTX &c);

~MY_CTX ();

MY_CTX & operator = (MY_CTX &c);

operator LIB_CTX * () const;

bool operator ! () const;
};
</C++ code>

Så ser det ud til at virke med Borland C++Builder V6, Microsoft Visual C++
..NET 2003 og g++ 3.2.



Det længere svar:

Det forekommer mig at der er design problem i indkapslingen af C
biblioteket.

Jeg ville dele problemet op i 2 uafhængige opgaver og dermed klasser:
1. Lave en C++ indkapsling af biblioteket
2. Håndtere levetid af objekter

1.
Jeg ville lave indkapslingen således at når man har et C++ objekt, så har
man også det underliggende context fra biblioteket. Der bliver således en
simpel en-til-en sammenhæng mellem C++ objekter og C biblioteks objekter.
Klassens invarians bliver simpel, og muligheden for forkert brug mindre.
Det vil kræve at man fjerner copy-constructor, copy-assignment, konversion
muligheder (af pragmatiske grund kan man forsigtigt tilføje dem igen) og
operator! fra klassen.
Desuden er der ingen så ingen grund til at have funktionen make_ctx - det
bliver blot endnu en constructor.


2.
Det er helt standard problematik.
Det kan sagtens være at spørgsmålet fuldstændigt forsvinder, men eller kan
klasser som std::auto_ptr eller smart-pointere fra Boost måske hjælpe.

<C++ code - ctx.h>
#ifndef GUARD_CTX_H
#define GUARD_CTX_H

#include "ctx_lib.h"

class ctx
{
public:
ctx();
ctx(int a_arg, int b_arg);

~ctx ();

void a(int a_arg);
void b(int b_arg);

LIB_CTX* get_lib_ctx(); // Here be dragons!!!

private:
LIB_CTX *lib_ctx;

private:
// copy-constructor and copy-assignment made
// private and not implemented to prevent accidental
// usage
ctx (const ctx &c);
ctx & operator = (ctx &c);
};

void use_ctx(ctx& ctx_arg);

#endif // GUARD_CTX_H
</C++ code - make_ctx.h>

<C++ code - make_ctx.cpp>
// make_ctx.cpp
#include "make_ctx.h"
#include <iostream>
#include <stdexcept>

using std::cout;
using std::endl;
using std::runtime_error;


ctx::ctx() :
lib_ctx(lib_make_ctx())
{
if(!lib_ctx)
throw runtime_error("Cannot make ctx");

cout << "constructor - lib_ctx = " << lib_ctx << endl;
}

ctx::ctx(int a_arg, int b_arg) :
lib_ctx(lib_make_ctx())
{
if(!lib_ctx)
throw runtime_error("Cannot make ctx");

try {
a(a_arg);
b(b_arg);
}
catch(...) {
throw;
}
cout << "constructor - lib_ctx = " << lib_ctx << endl;
}

ctx:ctx()
{
cout << "destructor - lib_ctx = " << lib_ctx << endl;
lib_free_ctx(lib_ctx);
}

void ctx::a(int a_arg)
{
if(lib_ctx_set_a(lib_ctx, a_arg))
throw runtime_error("Cannot set a");
}

void ctx::b(int b_arg)
{
if(lib_ctx_set_b(lib_ctx, b_arg))
throw runtime_error("Cannot set b");
}

LIB_CTX* ctx::get_lib_ctx()
{
return lib_ctx;
}

void use_ctx(ctx& ctx_arg)
{
lib_use_ctx(ctx_arg.get_lib_ctx());
}
</C++ code - make_ctx.cpp>

Venlig hilsen

Mogens Hansen




Byrial Jensen (05-10-2003)
Kommentar
Fra : Byrial Jensen


Dato : 05-10-03 08:49

Mogens Hansen wrote:
> "Byrial Jensen" <bjensen@nospam.dk> wrote
>
>>Hvorfor virker programmet ikke?
>
> Det korte svar:
>
> make_ctx returnerer et temporært objekt, som er en r-value - altså det kan
> ikke modificeres
> Din copy-constructor tager en ikke-const reference til et objekt, og kan
> derfor ikke bruges til at lave en kopi med.

Tak. Lige et ekstra spørgsmål: Ville det være korrekt at lave en
copy-constructor med et "const X&"-argument, men alligevel ændre
argumentet ved hjælp af et const_cast som foreslået fra anden side,
eller ville det give udefineret adfærd?

> Det længere svar:
>
> Det forekommer mig at der er design problem i indkapslingen af C
> biblioteket.
>
> Jeg ville dele problemet op i 2 uafhængige opgaver og dermed klasser:
> 1. Lave en C++ indkapsling af biblioteket
> 2. Håndtere levetid af objekter

Det ser interessant ud. Problemet med punkt 1 er bare at mit virkelige
C-bibliotek er meget stort (det er OpenSSL, og min "LIB_CTX" hedder i
virkeligheden SSL_CTX) og har temmelig mange funktioner som så skulle
indkapsles, hvilket ville give en masse ekstra kode som jeg umiddelbart
gerne vil undgå at lave da jeg nok mest ville tænke på det som
unødvendigt fyld.


Mogens Hansen (05-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 05-10-03 12:30


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:3F7FCCF6.9010701@nospam.dk...

[8<8<8<]
> Tak. Lige et ekstra spørgsmål: Ville det være korrekt at lave en
> copy-constructor med et "const X&"-argument, men alligevel ændre
> argumentet ved hjælp af et const_cast som foreslået fra anden side,
> eller ville det give udefineret adfærd?

Som jeg husker det:
Hvis et objekt er født som ikke-const, men man har en const reference til
det kan man lave const_cast med veldefineret opførsel.
Hvis et objekt er født som const, kan man ikke forvente veldefineret
opførsel hvis man laver const_cast.
Altså:
int j = 6;
cont int& jr = j;
const_cast<int&>(jr) = 3; // Well defined behaviour
const int i = 7;
const_cast<int&>(i) = 3; // Undefined behaviour

Alternativt kan data-medlemmet gøres mutable - som du har været inde på.

Du kunne også overveje at lade din klasse benytte reference counting til at
bestemme hvornår resourcen skal frigives til det underliggende bibliotek.
Det ville muligvis også kunne gøre tingene simplere.
Det er kendt og beskrevet at den måde at overdrage ejerskabet på, som
std::auto_ptr gør, er forbundet med nogle problemer.

[8<8<8<]
> Det ser interessant ud. Problemet med punkt 1 er bare at mit virkelige
> C-bibliotek er meget stort (det er OpenSSL, og min "LIB_CTX" hedder i
> virkeligheden SSL_CTX) og har temmelig mange funktioner som så skulle
> indkapsles,

Ja.
Er der andre, som allerede har lavet en C++ indpakning af OpenSSL ?

> hvilket ville give en masse ekstra kode som jeg umiddelbart
> gerne vil undgå at lave da jeg nok mest ville tænke på det som
> unødvendigt fyld.
>

Jeg forstår hvad du mener.
Men det vil bl.a. kunne give ensartet opførsel med hensyn til
fejlhåndtering.
Se på din oprindelige funktion "make_ctx", den smider exceptions hvis den
fejler.
Med dit oprindelig oplæg skal man kalde "lib_ctx_set_a" direkte med din
klasse vil der blive returneret en fejl kode.
Du har således 2 forskellige fejl-håndterings metoder at bekymre dig om.

Der kunne også være yderligere resource håndtering, som f.eks. først at
spørge til hvor stor en buffer der skal bruges, hvorefter man allokerer den,
hvorefter man kan hente den ønskede information, som så kan returneres som
f.eks. et std::string objekt. Det kender jeg i hvertfald fra andre C
baserede biblioteker.

Du behøver jo heller ikke at indkapsle hele biblioteket - man kunne nøjes
med den del man bruger.
Hvis de funktioner laves som inline, giver det ikke noget performance
overhead.


Venlig hilsen

Mogens Hansen



Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408924
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste