Connecting Tech Pros Worldwide Forums | Help | Site Map

beginner question

Lloyd Dupont
Guest
 
Posts: n/a
#1: Nov 17 '05
how do I redefine the new operator?
for all the structure I use at once!
(some of them comes from C include files).

The rationale:
I'm writting a managed C++ wrapper around C API (external headers &
structure definition).
it's very handy to use "new SCRIPT_ITEM[N];" however I want to handle
OutOfMemory gracefully,
that is dealloc everything 1st and then throw a managed exception, I also
want to initialize all my struct to 0 with new.

Also, if I have not enough memory in a C++ constructor, should the object
delete itself?





Tamas Demjen
Guest
 
Posts: n/a
#2: Nov 17 '05

re: beginner question


Lloyd Dupont wrote:[color=blue]
> how do I redefine the new operator?[/color]

The Effective C++ and/or More Effective C++ books discuss that topic,
among other books. It's not something you can explain in a few lines.
And it's not something you generally want to do yourself.
[color=blue]
> it's very handy to use "new SCRIPT_ITEM[N];" however I want to handle
> OutOfMemory gracefully,
> that is dealloc everything 1st and then throw a managed exception[/color]

There is nothing you have to deallocate if allocation fails. You can
catch the C++ exception and throw a managed one.
[color=blue]
> I also want to initialize all my struct to 0 with new.[/color]

It would be nice if C++ initialized everything to 0 automatically,
unless a special keyword is used (for the performance-oriented tasks).
But it's not the memory allocator's job, it needs to be done in the
constructor. What if you allocate the object on the stack? In that case
no new operator is called.
[color=blue]
> Also, if I have not enough memory in a C++ constructor, should the object
> delete itself?[/color]

If a class' constructor throws, the object is not considered existing.
Therefore you can't call delete on it, and its destructor is not called
either. So you should be careful about throwing from a constructor, at
least in native C++.

I recommend that you protect your allocations with smart pointers,
because in case a cosntructor throws, its members that have already been
initialized are gracefully destructed automatically.

Example:
class C
{
public:
C() : member(new int) { throw 0; }
~C() { delete member; }
private:
int* member;
};

This class is going to leak, because its constructor throws before
deleting the allocated member. You can avoid this leak by using auto_ptr:

class C
{
public:
C() : member(new int) { throw 0; }
private:
std::auto_ptr<int> member;
};

This time "member" is destructed automatically and there is no leak.
This is the only safe way of programming. I recommend boost::shared_ptr
for complex application, read my article "An Introduction to Boost
shared_ptr" for a full discussion:
http://tweakbits.com/

It's a good idea to write a class for every operation that needs to be
performed in pairs (open/close, allocate/deallocate, lock/unlock). This
technique is called RAII (resource acquisition is initialization), when
an extremely thin class is created just for resource lifetime
management. The resource is initialized in the constructor and is
uninitialized/released in the destructor. The class should be very thin
and should be used as member for larger classes. This way you're always
on the safe side.

Also be careful to create a physical variable for each allocation,
instead of passing allocations on the fly:

f(std::auto_ptr<T>(new T), std::auto_ptr<U>(new U); // UNSAFE!!!

This is not safe, because the order of execution of the calls is
undefined, and new may fail before auto_ptr has a chance to secure the
object. Don't try to save lines, do it the proper way:

std::auto_ptr<T> param1(new T);
std::auto_ptr<U> param2(new U);
f(param1, param2); // this is safe

Tom
Lloyd Dupont
Guest
 
Posts: n/a
#3: Nov 17 '05

re: beginner question


Hi Tom, thanks for your mail, my help me solve elegantly some problem I have.
2 questions though:

1st:
if there is a C function like that
void F(TYPE* p); // remark p is a pointer to an array
how do I call it with an
auto_ptr<TYPE> p; //??? p
could I just:
p = new
F(p); //???


2nd:
I will first submit an idea of solution without auto_ptr (an idea I had from an other post) for you to comment, and then a second listing with auto_ptr (to comment as well ;-)

BTW I had a quick read at your boost stuff but I don't really need it, very simple application, I will limit myself to standart stuff, easier to pick for next developer, no extra download... (but it's good stuff, I have to admit)

-- 1st listing -- what about that ? --

#include <someLibrary.h>

// my managed not enough memory exception!
static OutOfMemoryException^ NotEnoughMemory = gcnew OutOfMemoryException();

class MyClass
{
TYPE_1_T *var1, *var2, *var, *var4, *var5;
public:
MyClass(int aNumber) : var1(NULL), var2(NULL), var3(NULL), var4(NULL), var5(NULL)
{
try
{
// get the size of the arrays
int[] SIZES = new int[5]; // temp variable, could be leaked by an exception, problem.....
SomeOtherLibFunction( aNumber, 5, SIZES );

// some (memory) error throwing init code
var1 = new TYPE_1_T[ SIZES[1] ];
var2 = new TYPE_1_T[ SIZES[2] ];
var3 = new TYPE_1_T[ SIZES[3] ];
var4 = new TYPE_1_T[ SIZES[4] ];
var5 = new TYPE_1_T[ SIZES[5] ];

// ... some other code ...
blabla( var1 );

// delete temporary variable
// oops.. would leak if there is an exception before,
// in may case it's difficult to work around it's freed / allocated / adjusted in a loop
delete SIZES;
}
catch(std::bad_alloc)
{
// here I delete all my allocated var, what do you think?
~MyClass();
throw NotEnoughMemory ;
}
}
~MyClass()
{
if(var1)
delete var1;
if(var2)
delete var2;
if(var3)
delete var3;
if(var4)
delete var4;
if(var5)
delete var5;

// to prevent problem with multiple call
var1 = NULL;
var2 = NULL;
var3 = NULL;
var4 = NULL;
var5 = NULL;
}
}

-- 2nd listing -- what about that ? -- (I hope it's good as it's much more simple!) --

#include <someLibrary.h>
// include for auto_ptr ?! which header ?!
#include <auto_ptr>

// my managed not enough memory exception!
static OutOfMemoryException^ NotEnoughMemory = gcnew OutOfMemoryException();

using namespace std;

class MyClass
{
// here potential problem, would managed class accept auto_ptr<> variable type?
auto_ptr<TYPE_1_T> var1, var2, var, var4, var5;
public:
MyClass()
{
try
{
// get the size of the arrays, safe operation, nice!
auto_ptr<int[]> SIZES(new int[5]);
SomeOtherLibFunction( aNumber, 5, SISEZ );

// are these statments ok?
var1 = new TYPE_1_T[ SIZES[1] ];
var2 = new TYPE_1_T[ SIZES[2] ];
var3 = new TYPE_1_T[ SIZES[3] ];
var4 = new TYPE_1_T[ SIZES[4] ];
var5 = new TYPE_1_T[ SIZES[5] ];

// ... some other code ...
blabla( var1 );
}
catch(std::bad_alloc)
{
throw NotEnoughMemory ;
}
}
}
---



--
There are 10 kinds of people in this world. Those who understand binary and those who don't.
"Tamas Demjen" <tdemjen@yahoo.com> wrote in message news:eaZtg9dmFHA.3380@TK2MSFTNGP12.phx.gbl...[color=blue]
> Lloyd Dupont wrote:[color=green]
>> how do I redefine the new operator?[/color]
>
> The Effective C++ and/or More Effective C++ books discuss that topic,
> among other books. It's not something you can explain in a few lines.
> And it's not something you generally want to do yourself.
> [color=green]
>> it's very handy to use "new SCRIPT_ITEM[N];" however I want to handle
>> OutOfMemory gracefully,
>> that is dealloc everything 1st and then throw a managed exception[/color]
>
> There is nothing you have to deallocate if allocation fails. You can
> catch the C++ exception and throw a managed one.
> [color=green]
>> I also want to initialize all my struct to 0 with new.[/color]
>
> It would be nice if C++ initialized everything to 0 automatically,
> unless a special keyword is used (for the performance-oriented tasks).
> But it's not the memory allocator's job, it needs to be done in the
> constructor. What if you allocate the object on the stack? In that case
> no new operator is called.
> [color=green]
>> Also, if I have not enough memory in a C++ constructor, should the object
>> delete itself?[/color]
>
> If a class' constructor throws, the object is not considered existing.
> Therefore you can't call delete on it, and its destructor is not called
> either. So you should be careful about throwing from a constructor, at
> least in native C++.
>
> I recommend that you protect your allocations with smart pointers,
> because in case a cosntructor throws, its members that have already been
> initialized are gracefully destructed automatically.
>
> Example:
> class C
> {
> public:
> C() : member(new int) { throw 0; }
> ~C() { delete member; }
> private:
> int* member;
> };
>
> This class is going to leak, because its constructor throws before
> deleting the allocated member. You can avoid this leak by using auto_ptr:
>
> class C
> {
> public:
> C() : member(new int) { throw 0; }
> private:
> std::auto_ptr<int> member;
> };
>
> This time "member" is destructed automatically and there is no leak.
> This is the only safe way of programming. I recommend boost::shared_ptr
> for complex application, read my article "An Introduction to Boost
> shared_ptr" for a full discussion:
> http://tweakbits.com/
>
> It's a good idea to write a class for every operation that needs to be
> performed in pairs (open/close, allocate/deallocate, lock/unlock). This
> technique is called RAII (resource acquisition is initialization), when
> an extremely thin class is created just for resource lifetime
> management. The resource is initialized in the constructor and is
> uninitialized/released in the destructor. The class should be very thin
> and should be used as member for larger classes. This way you're always
> on the safe side.
>
> Also be careful to create a physical variable for each allocation,
> instead of passing allocations on the fly:
>
> f(std::auto_ptr<T>(new T), std::auto_ptr<U>(new U); // UNSAFE!!!
>
> This is not safe, because the order of execution of the calls is
> undefined, and new may fail before auto_ptr has a chance to secure the
> object. Don't try to save lines, do it the proper way:
>
> std::auto_ptr<T> param1(new T);
> std::auto_ptr<U> param2(new U);
> f(param1, param2); // this is safe
>
> Tom[/color]
Lloyd Dupont
Guest
 
Posts: n/a
#4: Nov 17 '05

re: beginner question


let me correct 1st question:

1st:
if there is a C function like that
void F(TYPE* p); // remark p is a pointer to an array
how do I call it with an
auto_ptr<TYPE> p;
could I just:
p = new TYPE[N];
F(p);
Lloyd Dupont
Guest
 
Posts: n/a
#5: Nov 17 '05

re: beginner question


I can't use auto_ptr in managed class :-(


Tamas Demjen
Guest
 
Posts: n/a
#6: Nov 17 '05

re: beginner question


Lloyd Dupont wrote:[color=blue]
> I can't use auto_ptr in managed class :-([/color]

Borrowing the idea from boost::scoped_ptr, I wrote a C++/CLI smart
pointer implementation for storing unmanaged pointers in managed
objects. You can find it in the end of this message. This concept only
works in VC++ 2005, and since the product is beta, I can't guarantee
that it's entirely correct nor that it will work 100% perfectly in the
final version. It has a slight overhead, of course, compared to manually
calling new and delete, just like every smart pointer does. I don't know
how well the compiler will optimize it.

Usage:

class Unmanaged
{
};

ref class Managed
{
private:
CliScopedPtr<Unmanaged> member;
};

If you want a smart pointer that encapsulates managed objects, Microsoft
has already provided such an implementation in STL.NET (STL/CLR), which
is included in the latest beta.

Tom

-----------------------------------------

#pragma once

template <class T>
public ref class CliScopedPtr
{
typedef CliScopedPtr<T> this_type;

public:
CliScopedPtr()
: ptr(nullptr)
{
}

explicit CliScopedPtr(T* p)
: ptr(p)
{
}

~CliScopedPtr()
{
delete ptr;
}

T* get()
{
return ptr;
}

T& operator*()
{
return *ptr;
}

T* operator->()
{
return ptr;
}

bool assigned()
{
return ptr != nullptr;
}

void swap(CliScopedPtr% other)
{
T* tmp = other.ptr;
other.ptr = ptr;
ptr = tmp;
}

void swap(CliScopedPtr^ other)
{
T* tmp = other->ptr;
other->ptr = ptr;
ptr = tmp;
}

void reset()
{
this_type().swap(this);
}

void reset(T* p)
{
this_type(p).swap(this);
}

private:
T* ptr;
CliScopedPtr(const CliScopedPtr%);
CliScopedPtr% operator=(const CliScopedPtr%);
};
Tamas Demjen
Guest
 
Posts: n/a
#7: Nov 17 '05

re: beginner question


Lloyd Dupont wrote:[color=blue]
> let me correct 1st question:
>
> 1st:
> if there is a C function like that
> void F(TYPE* p); // remark p is a pointer to an array
> how do I call it with an
> auto_ptr<TYPE> p;
> could I just:
> p = new TYPE[N];
> F(p);[/color]

No you can't use auto_ptr there.

Choice #1:
vector<TYPE> v;
F(&v[0]);

Choice #2:
#include <boost/scoped_array.hpp>
boost::scoped_array<TYPE> a(new TYPE[n]);
F(a.get());

Tom
Lloyd Dupont
Guest
 
Posts: n/a
#8: Nov 17 '05

re: beginner question


thanks Tamas, I should definetely look into all of that!

"Tamas Demjen" <tdemjen@yahoo.com> wrote in message
news:OJv1VGQnFHA.3544@TK2MSFTNGP15.phx.gbl...[color=blue]
> Lloyd Dupont wrote:[color=green]
>> I can't use auto_ptr in managed class :-([/color]
>
> Borrowing the idea from boost::scoped_ptr, I wrote a C++/CLI smart pointer
> implementation for storing unmanaged pointers in managed objects. You can
> find it in the end of this message. This concept only works in VC++ 2005,
> and since the product is beta, I can't guarantee that it's entirely
> correct nor that it will work 100% perfectly in the final version. It has
> a slight overhead, of course, compared to manually calling new and delete,
> just like every smart pointer does. I don't know how well the compiler
> will optimize it.
>
> Usage:
>
> class Unmanaged
> {
> };
>
> ref class Managed
> {
> private:
> CliScopedPtr<Unmanaged> member;
> };
>
> If you want a smart pointer that encapsulates managed objects, Microsoft
> has already provided such an implementation in STL.NET (STL/CLR), which is
> included in the latest beta.
>
> Tom
>
> -----------------------------------------
>
> #pragma once
>
> template <class T>
> public ref class CliScopedPtr
> {
> typedef CliScopedPtr<T> this_type;
>
> public:
> CliScopedPtr()
> : ptr(nullptr)
> {
> }
>
> explicit CliScopedPtr(T* p)
> : ptr(p)
> {
> }
>
> ~CliScopedPtr()
> {
> delete ptr;
> }
>
> T* get()
> {
> return ptr;
> }
>
> T& operator*()
> {
> return *ptr;
> }
>
> T* operator->()
> {
> return ptr;
> }
>
> bool assigned()
> {
> return ptr != nullptr;
> }
>
> void swap(CliScopedPtr% other)
> {
> T* tmp = other.ptr;
> other.ptr = ptr;
> ptr = tmp;
> }
>
> void swap(CliScopedPtr^ other)
> {
> T* tmp = other->ptr;
> other->ptr = ptr;
> ptr = tmp;
> }
>
> void reset()
> {
> this_type().swap(this);
> }
>
> void reset(T* p)
> {
> this_type(p).swap(this);
> }
>
> private:
> T* ptr;
> CliScopedPtr(const CliScopedPtr%);
> CliScopedPtr% operator=(const CliScopedPtr%);
> };[/color]


Lloyd Dupont
Guest
 
Posts: n/a
#9: Nov 17 '05

re: beginner question


aheum....well I'm still confused with STL.
Anyway your sample inspire me this very C style (as opposed to C++ style) template which fit my need 100%.
what do you think?

(note I put the destructor in the private part, seems safer to me, no?)
------------------------
#pragma once
#include "stdlib.h"

template <class T>
public ref class CliAutoArray : System::IDisposable
{
public:
CliAutoArray(int capacity) : length(capacity)
{
if(length < 0)
throw gcnew ArgumentOutOfRangeExeption();
ptr = (T*) malloc(length * sizeof(T));
if( !ptr )
throw gcnew OutOfMemoryException();
}

T* Get() { return ptr; }

property int Length
{
int get() { return length; }
void set(int newlength)
{
if(newlength < 0)
throw gcnew ArgumentOutOfRangeExeption();

T* newptr = (T*) realloc((void*) ptr, newlength * sizeof(T));
if( !newptr )
throw gcnew OutOfMemoryException();

ptr = newptr;
}
}
T* operator[](int index)
{
// just be careful, OK?!
//if(index < 0 || index >= length)
// throw gcnew ArgumentOutOfRangeExeption();
return ptr+index;
}
private:
~CliAutoArray()
{
if( ptr ) // I'm not sure of what IDisposable will do...
ptr;
ptr = nullptr;
}
int length;
T* ptr;
CliAutoArray(const CliAutoArray%);
CliAutoArray% operator=(const CliAutoArray%);
};

Lloyd Dupont
Guest
 
Posts: n/a
#10: Nov 17 '05

re: beginner question


well, I just realized that I could just use a
array<Unmanaged>^ na = gcnew array<Unmanaged>[N];
pin_ptr<Unmanaged> pna = &na[0];

but well, I realized it later.. furthermore I could decrease GC work significantly with this class as I might do heaps of realloc...
"Lloyd Dupont" <net.galador@ld> wrote in message news:eiIWeCUnFHA.2852@TK2MSFTNGP15.phx.gbl...
aheum....well I'm still confused with STL.
Anyway your sample inspire me this very C style (as opposed to C++ style) template which fit my need 100%.
what do you think?

(note I put the destructor in the private part, seems safer to me, no?)
------------------------
#pragma once
#include "stdlib.h"

template <class T>
public ref class CliAutoArray : System::IDisposable
{
public:
CliAutoArray(int capacity) : length(capacity)
{
if(length < 0)
throw gcnew ArgumentOutOfRangeExeption();
ptr = (T*) malloc(length * sizeof(T));
if( !ptr )
throw gcnew OutOfMemoryException();
}

T* Get() { return ptr; }

property int Length
{
int get() { return length; }
void set(int newlength)
{
if(newlength < 0)
throw gcnew ArgumentOutOfRangeExeption();

T* newptr = (T*) realloc((void*) ptr, newlength * sizeof(T));
if( !newptr )
throw gcnew OutOfMemoryException();

ptr = newptr;
}
}
T* operator[](int index)
{
// just be careful, OK?!
//if(index < 0 || index >= length)
// throw gcnew ArgumentOutOfRangeExeption();
return ptr+index;
}
private:
~CliAutoArray()
{
if( ptr ) // I'm not sure of what IDisposable will do...
ptr;
ptr = nullptr;
}
int length;
T* ptr;
CliAutoArray(const CliAutoArray%);
CliAutoArray% operator=(const CliAutoArray%);
};

Lloyd Dupont
Guest
 
Posts: n/a
#11: Nov 17 '05

re: beginner question


of course I meant:
~CliAutoArray()
{
if( ptr ) // I'm not sure of what IDisposable will do...
free( ptr );

Closed Thread