beginner question

L

Lloyd Dupont

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?
 
T

Tamas Demjen

Lloyd said:
how do I redefine the new operator?

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.
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

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

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.
Also, if I have not enough memory in a C++ constructor, should the object
delete itself?

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
 
L

Lloyd Dupont

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 said:
Lloyd said:
how do I redefine the new operator?

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.
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

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

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.
Also, if I have not enough memory in a C++ constructor, should the object
delete itself?

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
 
L

Lloyd Dupont

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);
 
T

Tamas Demjen

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

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%);
};
 
T

Tamas Demjen

Lloyd said:
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);

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
 
L

Lloyd Dupont

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%);
};
 
L

Lloyd Dupont

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...
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%);
};
 
L

Lloyd Dupont

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top