473,473 Members | 1,935 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

creating with new and destroying with free

I am writing some C++ wrappers around some legacy C ones - more
specifically, I am providing ctors, dtors and assignment operators for
the C structs.

I have a ton of existing C code that uses these structs. A typical usage
case will be as ff (note the code below is Pseudocode and WILL NOT compile)

//example structs (I have left out the ctors/dtors etc for brevity sake)

struct MyStructA
{
char name[4];
long x;
long y ;
int z ;
};
struct MyStructB
{
long a ;
long b ;
MyStructA * struct_array ;
long allocedsize ;
long numstructs ;
char key[16];
};
struct MyStructC
{
long g ;
long h ;
MyStructB * struct_array ;
long allocedsize ;
long numstructs ;
};

//example C API funcs (ignore null ptrs for now)

void foo_addB(MyStructC* p1, MyStructB* p2)
{
//logic to determine if there is enough room in the
// array for a new struct, if not malloc some more, then
// get position (pos) in array of new struct
memcpy(&p1->struct_array[pos], p2, sizeof(MyStructB));
}
void foo_removeB(MyStructC* p1, const size_t pos)
{
//logic to validate speicified pos (return if !valid)
free(&p1->struct_array[pos]) ;
p1->struct_array[pos] =0 ;
}

//C++ code
bool SomeClass::Method1(MyStructC* arg)
{
//object created on stack
MyStructB b ; //C++ default ctor called (code not shown)

//calls C function
foo_addB( arg, &b) ;
}

bool SomeClass::Method2(MyStructC* arg)
{
//object storage alloced from heap
MyStructB * b = new MyStructB() ; //C++ default ctor called (code
not shown)

//calls C function
foo_addB( arg, b) ;
}
bool SomeClass::Method3(MyStructC* arg)
{
//object storage alloced from heap
MyStructB * b = reinterpret_cast<MyStructB*>(calloc( 1, MyStructB())) ;

//calls C function
foo_addB( arg, b) ;
}


Notes:
======
Because the assignments in the C code are "shallow" copies (C struct
assignment), the copy assignement operators for the structs are also
"shallow", though I have provided explicit methods on the structs to
facilitate "deep" copying.
I have the ff questions:
==========================
Bearing in mind that the C API only carries out a 'shallow' copy which
of the 3 C++ methods above are correct (atleast in the sense that they
will not leak memory, and will not attempt to delete memory twice)?
Here are my observersations/thoughts so far:

SomeClass::Method1()
This will not leak memory (created on stack), but when it goes out of
memory, when foo_removeB() is called, we will be attempting to free an
invalid ptr (also, I suspect, the variable was implicity created by new
behind the scenes - if this is the case trhen there is the [potential?]
issue of destroying with free, an object created with new() ).

SomeClass::Method2()
This will no doubt leak memory - since I am not deleting after the new,
also, there is the issue of destroying an object created with new, by
calling free

SomeClass::Method3()
This seems to be the "best" solution in that memory is alloced from the
heap, and we explicitly specify calloc - so (hopefully), calling free on
this pointer should be ok?
My questions are
==================
i). Is my thinking (so far) correct?
ii). Is there anything I may be overlooking ?
iii). What is the best way to create a struct in C++ code and pass to
the C API functions foo_addB() and foo_removeB()?
Jun 4 '07 #1
3 2253
Bartholomew Simpson wrote:
:: I am writing some C++ wrappers around some legacy C ones - more
:: specifically, I am providing ctors, dtors and assignment operators
:: for
:: the C structs.

And that makes them C++ struct. See below!

::
:: I have a ton of existing C code that uses these structs. A typical
:: usage case will be as ff (note the code below is Pseudocode and
:: WILL NOT compile)
::
:: //example structs (I have left out the ctors/dtors etc for brevity
:: sake)
::
:: struct MyStructA
:: {
:: char name[4];
:: long x;
:: long y ;
:: int z ;
:: };
::
::
:: struct MyStructB
:: {
:: long a ;
:: long b ;
:: MyStructA * struct_array ;
:: long allocedsize ;
:: long numstructs ;

The three lines above is pretty much what a std::vector is. Why not
consider using one?

:: char key[16];
:: };
::
::
:: struct MyStructC
:: {
:: long g ;
:: long h ;
:: MyStructB * struct_array ;
:: long allocedsize ;
:: long numstructs ;

Here's another std::vector, I guess.

:: };
::
::
::
:: //example C API funcs (ignore null ptrs for now)
::
:: void foo_addB(MyStructC* p1, MyStructB* p2)
:: {
:: //logic to determine if there is enough room in the
:: // array for a new struct, if not malloc some more, then
:: // get position (pos) in array of new struct
:: memcpy(&p1->struct_array[pos], p2, sizeof(MyStructB));

Here you get into trouble. If your struct has a constructor or a
destructor, it is no longer memcpy compatible.

:: }
::
::
:: void foo_removeB(MyStructC* p1, const size_t pos)
:: {
:: //logic to validate speicified pos (return if !valid)
:: free(&p1->struct_array[pos]) ;

Who is calling the destructor for this object?
:: p1->struct_array[pos] =0 ;
:: }
::
::
::
:: //C++ code
:: bool SomeClass::Method1(MyStructC* arg)
:: {
:: //object created on stack
:: MyStructB b ; //C++ default ctor called (code not shown)
::
:: //calls C function
:: foo_addB( arg, &b) ;
:: }
::
::
::
:: bool SomeClass::Method2(MyStructC* arg)
:: {
:: //object storage alloced from heap
:: MyStructB * b = new MyStructB() ; //C++ default ctor called
:: (code
:: not shown)
::
:: //calls C function
:: foo_addB( arg, b) ;
:: }
::
::
:: bool SomeClass::Method3(MyStructC* arg)
:: {
:: //object storage alloced from heap
:: MyStructB * b = reinterpret_cast<MyStructB*>(calloc( 1,
:: MyStructB())) ;

This really doesn't work at all.

::
:: //calls C function
:: foo_addB( arg, b) ;
:: }
::
::
::
::
:: Notes:
:: ======
:: Because the assignments in the C code are "shallow" copies (C
:: struct assignment), the copy assignement operators for the structs
:: are also "shallow", though I have provided explicit methods on the
:: structs to facilitate "deep" copying.

If you want shallow copies, you don't have to write the assignment
operator. The compiler will do that for you, as a default.

::
::
:: I have the ff questions:
:: ==========================
:: Bearing in mind that the C API only carries out a 'shallow' copy
:: which
:: of the 3 C++ methods above are correct (atleast in the sense that
:: they will not leak memory, and will not attempt to delete memory
:: twice)?
::
::
:: Here are my observersations/thoughts so far:
::
:: SomeClass::Method1()
:: This will not leak memory (created on stack), but when it goes out
:: of memory, when foo_removeB() is called, we will be attempting to
:: free an invalid ptr (also, I suspect, the variable was implicity
:: created by new behind the scenes - if this is the case trhen there
:: is the [potential?] issue of destroying with free, an object
:: created with new() ).

No, there is no new calls behind the scene. The object is constructed
on the stack, and destructed at the end of the function.

As you make a copy the object (if memcpy were allowed), you free the
copy, not the original.

There might be a problem though with the shallow copy, but as we don't
know what struct_array points to, we cannot be sure how it should be
handled.

::
:: SomeClass::Method2()
:: This will no doubt leak memory - since I am not deleting after the
:: new, also, there is the issue of destroying an object created
:: with new, by calling free

You are actually free'ing a copy (if only memcpy was allowed :-).

::
:: SomeClass::Method3()
:: This seems to be the "best" solution in that memory is alloced
:: from the heap, and we explicitly specify calloc - so (hopefully),
:: calling free on this pointer should be ok?

I think you are trying too hard here.

If you want to do this the C++ way, and don't HAVE to keep the C API,
you could try storing the objects in a std::vector member of the
struct. Then you just do v.push_back(object), and the storage and the
construction/destruction will be managed automagically. That's it!

::
::
:: My questions are
:: ==================
:: i). Is my thinking (so far) correct?
:: ii). Is there anything I may be overlooking ?
:: iii). What is the best way to create a struct in C++ code and pass
:: to the C API functions foo_addB() and foo_removeB()?

If you really need a C struct, you have to keep it a C struct. If you
add C++ features to it, it is a C++ struct (and incompatible).
Bo Persson
Jun 4 '07 #2


Bo Persson wrote:
Bartholomew Simpson wrote:
:: I am writing some C++ wrappers around some legacy C ones - more
:: specifically, I am providing ctors, dtors and assignment operators
:: for
:: the C structs.

And that makes them C++ struct. See below!

::
:: I have a ton of existing C code that uses these structs. A typical
:: usage case will be as ff (note the code below is Pseudocode and
:: WILL NOT compile)
::
:: //example structs (I have left out the ctors/dtors etc for brevity
:: sake)
::
:: struct MyStructA
:: {
:: char name[4];
:: long x;
:: long y ;
:: int z ;
:: };
::
::
:: struct MyStructB
:: {
:: long a ;
:: long b ;
:: MyStructA * struct_array ;
:: long allocedsize ;
:: long numstructs ;

The three lines above is pretty much what a std::vector is. Why not
consider using one?
Ah, if life were but that simple. The C structs are much hairier than
that (in that they are nested to several layers), I simply posted some
simple structs hre, since posting the original structs in all their gory
detail would only serve as a red herring and simply confuse the core issue.
:: char key[16];
:: };
::
::
:: struct MyStructC
:: {
:: long g ;
:: long h ;
:: MyStructB * struct_array ;
:: long allocedsize ;
:: long numstructs ;

Here's another std::vector, I guess.

:: };
::
::
::
:: //example C API funcs (ignore null ptrs for now)
::
:: void foo_addB(MyStructC* p1, MyStructB* p2)
:: {
:: //logic to determine if there is enough room in the
:: // array for a new struct, if not malloc some more, then
:: // get position (pos) in array of new struct
:: memcpy(&p1->struct_array[pos], p2, sizeof(MyStructB));

Here you get into trouble. If your struct has a constructor or a
destructor, it is no longer memcpy compatible.
Hello!, this IS news to me ..... *shakes head in disbelief*
>
:: }
::
::
:: void foo_removeB(MyStructC* p1, const size_t pos)
:: {
:: //logic to validate speicified pos (return if !valid)
:: free(&p1->struct_array[pos]) ;

Who is calling the destructor for this object?

Erm, its a C API library function - there is no "owner" as such ... its
just a function in the library. Theooretically, it can be called by any
func that supplies the correct args, though in practice, it is only used
within a graphics library.
:: p1->struct_array[pos] =0 ;
:: }
::
::
::
:: //C++ code
:: bool SomeClass::Method1(MyStructC* arg)
:: {
:: //object created on stack
:: MyStructB b ; //C++ default ctor called (code not shown)
::
:: //calls C function
:: foo_addB( arg, &b) ;
:: }
::
::
::
:: bool SomeClass::Method2(MyStructC* arg)
:: {
:: //object storage alloced from heap
:: MyStructB * b = new MyStructB() ; //C++ default ctor called
:: (code
:: not shown)
::
:: //calls C function
:: foo_addB( arg, b) ;
:: }
::
::
:: bool SomeClass::Method3(MyStructC* arg)
:: {
:: //object storage alloced from heap
:: MyStructB * b = reinterpret_cast<MyStructB*>(calloc( 1,
:: MyStructB())) ;

This really doesn't work at all.
Why?. (I suppose reinterpret_cast does not like memory blocks not
alloc'd by new()?) I suppose its back to old C style casts then ...
>
::
:: //calls C function
:: foo_addB( arg, b) ;
:: }
::
::
::
::
:: Notes:
:: ======
:: Because the assignments in the C code are "shallow" copies (C
:: struct assignment), the copy assignement operators for the structs
:: are also "shallow", though I have provided explicit methods on the
:: structs to facilitate "deep" copying.

If you want shallow copies, you don't have to write the assignment
operator. The compiler will do that for you, as a default.
Thanks for the reminder
::
::
:: I have the ff questions:
:: ==========================
:: Bearing in mind that the C API only carries out a 'shallow' copy
:: which
:: of the 3 C++ methods above are correct (atleast in the sense that
:: they will not leak memory, and will not attempt to delete memory
:: twice)?
::
::
:: Here are my observersations/thoughts so far:
::
:: SomeClass::Method1()
:: This will not leak memory (created on stack), but when it goes out
:: of memory, when foo_removeB() is called, we will be attempting to
:: free an invalid ptr (also, I suspect, the variable was implicity
:: created by new behind the scenes - if this is the case trhen there
:: is the [potential?] issue of destroying with free, an object
:: created with new() ).

No, there is no new calls behind the scene. The object is constructed
on the stack, and destructed at the end of the function.

As you make a copy the object (if memcpy were allowed), you free the
copy, not the original.

There might be a problem though with the shallow copy, but as we don't
know what struct_array points to, we cannot be sure how it should be
handled.

::
:: SomeClass::Method2()
:: This will no doubt leak memory - since I am not deleting after the
:: new, also, there is the issue of destroying an object created
:: with new, by calling free

You are actually free'ing a copy (if only memcpy was allowed :-).
I'm not sure I follow you ... memcpy DOES NOT free memory after copying
a block of memory ... so I don't understand what youre saying - please
elaborate further.
>
::
:: SomeClass::Method3()
:: This seems to be the "best" solution in that memory is alloced
:: from the heap, and we explicitly specify calloc - so (hopefully),
:: calling free on this pointer should be ok?

I think you are trying too hard here.

If you want to do this the C++ way, and don't HAVE to keep the C API,
you could try storing the objects in a std::vector member of the
struct. Then you just do v.push_back(object), and the storage and the
construction/destruction will be managed automagically. That's it!
I HAVE to use the C library - that is the whole point. I need to find a
SAFE way of creating the structs in C++ and then passing them to C
libray functions that will directly access the nested structures and on
occasion, free memory (ptr to nested struct) that was allocated in the
C++ code - it sounds more complicated than it really is - this kind of
stuff is done in C all the time, though it may seem fiddly to "pure" C++
programmers. I really need advice from someone who has a strong
background in C as well (as opposed to C++ only) - the reason I posted
in this ng rather than the comp.lang.c ng is that the probs I am having
are from the C++ end - the C++ library works fine (has been for the last
10yrs or so).
::
::
:: My questions are
:: ==================
:: i). Is my thinking (so far) correct?
:: ii). Is there anything I may be overlooking ?
:: iii). What is the best way to create a struct in C++ code and pass
:: to the C API functions foo_addB() and foo_removeB()?

If you really need a C struct, you have to keep it a C struct. If you
add C++ features to it, it is a C++ struct (and incompatible).
Hmm, this is simply not true
>
Bo Persson

Jun 4 '07 #3
Bartholomew Simpson wrote:
:: Bo Persson wrote:
::
::: Bartholomew Simpson wrote:
::::: I am writing some C++ wrappers around some legacy C ones - more
::::: specifically, I am providing ctors, dtors and assignment
::::: operators for
::::: the C structs.
:::
::: And that makes them C++ struct. See below!
:::
:::::
::::: I have a ton of existing C code that uses these structs. A
::::: typical usage case will be as ff (note the code below is
::::: Pseudocode and WILL NOT compile)
:::::
::::: //example structs (I have left out the ctors/dtors etc for
::::: brevity sake)
:::::
::::: struct MyStructA
::::: {
::::: char name[4];
::::: long x;
::::: long y ;
::::: int z ;
::::: };
:::::
:::::
::::: struct MyStructB
::::: {
::::: long a ;
::::: long b ;
::::: MyStructA * struct_array ;
::::: long allocedsize ;
::::: long numstructs ;
:::
::: The three lines above is pretty much what a std::vector is. Why
::: not consider using one?
:::
::
:: Ah, if life were but that simple. The C structs are much hairier
:: than
:: that (in that they are nested to several layers), I simply posted
:: some simple structs hre, since posting the original structs in all
:: their gory detail would only serve as a red herring and simply
:: confuse the core issue.

Ok...

I'm just saying that std::vector has size(), capacity(), and a buffer.
If you don't HAVE TO manage this by hand, just don't!

:::::
::::: //example C API funcs (ignore null ptrs for now)
:::::
::::: void foo_addB(MyStructC* p1, MyStructB* p2)
::::: {
::::: //logic to determine if there is enough room in the
::::: // array for a new struct, if not malloc some more, then
::::: // get position (pos) in array of new struct
::::: memcpy(&p1->struct_array[pos], p2, sizeof(MyStructB));
:::
::: Here you get into trouble. If your struct has a constructor or a
::: destructor, it is no longer memcpy compatible.
::
:: Hello!, this IS news to me ..... *shakes head in disbelief*

You're in for a treat! :-)

The short version is that memcpy is a C style function that works for
C style objects. That's it.

The long version is that C++ is just different (better :-). As soon as
you add C++ features to your struct, it is equivalent to a class, and
must follow class rules. C++ defines C data types as PODs
(plain-old-data). PODs follow C rules, non-PODs do not have to.

Starting out with section 8.5.1 of the C++ Standard:

"An aggregate is an array or class (clause 9) with no user declared
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3)."

And then in section 9, Classes:

"A POD-struct is an aggregate class that has no non-static data
members of type non-POD-struct, non-POD-union (or array of such types)
or reference, and has no user-defined copy assignment operator and no
user defined destructor."

So, in C++ you can do a lot more than in C. But as soon as you do, you
must follow the new rules!
:::::
::::: bool SomeClass::Method3(MyStructC* arg)
::::: {
::::: //object storage alloced from heap
::::: MyStructB * b = reinterpret_cast<MyStructB*>(calloc( 1,
::::: MyStructB())) ;
:::
::: This really doesn't work at all.
::
:: Why?. (I suppose reinterpret_cast does not like memory blocks not
:: alloc'd by new()?) I suppose its back to old C style casts then ...

NO! No C-style casts! :-)

reinterpret_cast<is fine (as a last resort) when doing tricky
things. The problem here is that you would have to start out with

calloc(1, sizeof(MyStructB))

to get the proper size. But you will still have the problem of "who
calls the constructor". The C++ "new"-statement was invented to solve
this problem - it allocates space AND constructs an object in that
space. The calloc function allocates space, and fills it with zero.
Who says an object is all zero?!

:::::
::::: SomeClass::Method2()
::::: This will no doubt leak memory - since I am not deleting after
::::: the new, also, there is the issue of destroying an object
::::: created with new, by calling free
:::
::: You are actually free'ing a copy (if only memcpy was allowed :-).
::
:: I'm not sure I follow you ... memcpy DOES NOT free memory after
:: copying
:: a block of memory ... so I don't understand what youre saying -
:: please elaborate further.

memcpy creates a copy of (the bits of) the object. The space allocated
to struct_array is free'ed later (I guess). I just say that copying a
C++ object with memcpy isn't guaranteed to work. THAT is the problem -
you are not logically copying the object, only its bits. This is where
C++ differs from C...
::
:::
:::::
::::: SomeClass::Method3()
::::: This seems to be the "best" solution in that memory is alloced
::::: from the heap, and we explicitly specify calloc - so
::::: (hopefully), calling free on this pointer should be ok?
:::
::: I think you are trying too hard here.
:::
::: If you want to do this the C++ way, and don't HAVE to keep the C
::: API, you could try storing the objects in a std::vector member of
::: the struct. Then you just do v.push_back(object), and the storage
::: and the construction/destruction will be managed automagically.
::: That's it!
:::
::
:: I HAVE to use the C library - that is the whole point. I need to
:: find a SAFE way of creating the structs in C++ and then passing
:: them to C
:: libray functions that will directly access the nested structures
:: and on occasion, free memory (ptr to nested struct) that was
:: allocated in the
:: C++ code - it sounds more complicated than it really is - this
:: kind of stuff is done in C all the time, though it may seem fiddly
:: to "pure" C++ programmers. I really need advice from someone who
:: has a strong
:: background in C as well (as opposed to C++ only) - the reason I
:: posted
:: in this ng rather than the comp.lang.c ng is that the probs I am
:: having
:: are from the C++ end - the C++ library works fine (has been for
:: the last 10yrs or so).

The thing is that C compatible structs can (almost) only use C
features. As soon as you add anything of what I quoted above - private
or protected data, base classes, non-POD members, constructors,
destructors, assignment operators, or virtual functions - you leave C
and enter C++.

That means no bitwise copy (memcpy), but copying objects (std::copy).
You must also match allocation and deallocation - malloc/calloc/free,
new/delete, new[]/delete[]. There are no exceptions to this, if you
want your code to be portable. Sorry!
::
:::::
:::::
::::: My questions are
::::: ==================
::::: i). Is my thinking (so far) correct?
::::: ii). Is there anything I may be overlooking ?
::::: iii). What is the best way to create a struct in C++ code and
::::: pass to the C API functions foo_addB() and foo_removeB()?
:::
::: If you really need a C struct, you have to keep it a C struct. If
::: you add C++ features to it, it is a C++ struct (and incompatible).
:::
::
:: Hmm, this is simply not true

I believe it is, unfortunately.
Bo Persson
Jun 4 '07 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
by: Fuzzyman | last post by:
Pythons internal 'pointers' system is certainly causing me a few headaches..... When I want to copy the contents of a variable I find it impossible to know whether I've copied the contents *or*...
4
by: H?seyin | last post by:
I'm calling a function from a C DLL in .NET(C#). The func. seems so: void Sample(char *s) { s= calloc(6,1); strcpy(s, "hello"); }
0
by: Claire | last post by:
At the moment I am reading, realtime, upto 400 records every 250ms from a tcp connection. This batch is filtered, converted to a set of different types of record, added to an array ready for...
1
by: Ian Lazarus | last post by:
Hello, Since value classes are not managed by the garbage collector and can't have destructors but can have member data allocated on the C++ heap, how does this data get destroyed? For example, ...
9
by: Maziar Aflatoun | last post by:
Hi everyone, I like to export some data from the database and allow my users to store this file to their harddrive as a .txt file. Does anyone know how I would go about doing that? (without...
4
by: Olumide | last post by:
Hello - I have two classes A and B as follows: class B{ public: ~B(){ cout << "destroying B" << endl; } }; class A{
9
by: =?Utf-8?B?YmJn?= | last post by:
Hi all, I read somewhere "using kernel stuff in thread is not good.." if ManualResetEvent object is created in thread but not actually used, will it affect performance? Bob
14
by: pereges | last post by:
This program simply reads a list of employes from the user, prints it and then destroys the allocated memory. I have a function free_memory(void *ptr) which will free the memory pointed to by...
41
by: =?Utf-8?B?VGltIE1hcnNkZW4=?= | last post by:
Hi, I am after suggestions on the best practice declaring and destroying objects. some example code: Private Sub MySub Dim frmMyForm As MyForm Try
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.