• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
ultramailman

freeing pointer to const

11 posts in this topic

Hello, this bothered me for a long time...
How do I correctly free something that is pointed to by a pointer to const?

Look at this:
[CODE]
struct pair{
void const * key;
void const * val;
};
[/CODE]

Here I have a struct that is to be used for hash tables. I make them const because the keys are not supposed to change while they are inside a hash table. If the key is changed, that would mess up the table. This helped a lot, compilation would fail if I accidentaly modify the key. This is all good until I am finished with the pair and decide to free the key and val:

[CODE]void free(void * ptr);[/CODE]

If I try to free key, compilation fails, because the prototype of free makes no guarantees of not modifying whatever is passed in, like this:

[CODE]void free(void const * ptr);[/CODE]

Right now, I handle this by casting the pointer to non const, then free it:

[CODE]
void FREE(void const * ptr)
{
free((void *)ptr);
}
[/CODE]

This lets me compile, but it looks evil.

After searching around, I found kfree:

[CODE]void kfree(const void *objp);[/CODE]

But I can't use that, because it is part of linux, and not of the C standard.

Am I just being paranoid, and casting to non const is fine? Or is there another solution? Assuming struct pair is opaque, and key and val are always malloced and memcpy of argument pointers.
0

Share this post


Link to post
Share on other sites
The only really clean way is to rewrite your logic. Everything else is a hack.
E.g. instead of using a struct pair, use a class and add some const accessor and some friend none-const manipulator for the class, which should be able to clean it up.

[CODE]
friend class HashMap;
class pair {
private:
void *key;
void *val;
protected:
void* getKey()...
void setKey(void* ...)
public:
const void getKey();
const void getValue();
}
[/CODE]
0

Share this post


Link to post
Share on other sites
[quote name='Ashaman73' timestamp='1352970291' post='5001155']
The only really clean way is to rewrite your logic. Everything else is a hack.
E.g. instead of using a struct pair, use a class and add some const accessor and some friend none-const manipulator for the class, which should be able to clean it up.

[CODE]
friend class HashMap;
class pair {
private:
void *key;
void *val;
protected:
void* getKey()...
void setKey(void* ...)
public:
const void getKey();
const void getValue();
}
[/CODE]
[/quote]

Sorry friend, but I can't use classes in C
1

Share this post


Link to post
Share on other sites
[quote name='Ashaman73' timestamp='1352970291' post='5001155']
E.g. instead of using a struct pair, use a class and add some const accessor and some friend none-const manipulator for the class, which should be able to clean it up.[/quote]

Although not actually incorrect, I object to that because the choice of words reinforcess the common fallacy that struct and class are something different in C++. They are exactly the same and completely interchangeably, except for the fact that structs are public by default (for both accessibility and inheritance) and classes are private by default.

That said, this argument only pertains to C++ anyway. I'm not very fluent in C, but shouldn't something like this be some kind of solution?
[code]
// header
struct pair;
const void* getKey(struct pair*);
const void* getValue(struct pair*);

// implementation
struct pair
{
void* key;
void* val;
};

const void* getKey(struct pair* p)
{
return p->key;
}

const void* getKey(struct pair* p)
{
return p->val;
}
[/code]

Then you need some kind of similar allocator/free functions and some mutators and you have transferred the C++ way of doing things into C. Kinda. In a way. Well, not really but it's the best I can think of right now. Unless someone who knows his wayaround around actual C comes around it might be your best option.
0

Share this post


Link to post
Share on other sites
[quote name='BitMaster' timestamp='1352972468' post='5001170']
[quote name='Ashaman73' timestamp='1352970291' post='5001155']
E.g. instead of using a struct pair, use a class and add some const accessor and some friend none-const manipulator for the class, which should be able to clean it up.[/quote]

Although not actually incorrect, I object to that because the choice of words reinforcess the common fallacy that struct and class are something different in C++. They are exactly the same and completely interchangeably, except for the fact that structs are public by default (for both accessibility and inheritance) and classes are private by default.

That said, this argument only pertains to C++ anyway. I'm not very fluent in C, but shouldn't something like this be some kind of solution?
[code]
// header
struct pair;
const void* getKey(struct pair*);
const void* getValue(struct pair*);

// implementation
struct pair
{
void* key;
void* val;
};

const void* getKey(struct pair* p)
{
return p->key;
}

const void* getKey(struct pair* p)
{
return p->val;
}
[/code]

Then you need some kind of similar allocator/free functions and some mutators and you have transferred the C++ way of doing things into C. Kinda. In a way. Well, not really but it's the best I can think of right now. Unless someone who knows his wayaround around actual C comes around it might be your best option.
[/quote]

... I've never thought of it this way. I guess I got too used to directly accessing fields of non opaque structs. Sometimes the most obvious solutions are right there, but I just can't see it. Thanks, this works nicely.

But if anyone has something else, please post ;o
0

Share this post


Link to post
Share on other sites
The semantics of your key and value is that they are mutable, just not in arbitrary ways. You can free them but not modify them otherwise.
Thus the "evil" part is declaring them "void const *" - not casting them to "void *" in free().

But usually you do not worry about such things in C. It is not perfectly type-safe language and was never intended to be. Thus whatever works and is closest to the actual semantics (without inventing too many hacks) is usually the best.
0

Share this post


Link to post
Share on other sites
The type of your key, const void *, implicitly means that you should not free it. It points to a block of memory which is not writable, while "free" will destroy that memory, they are conflicting with each other.

You know you can free the key because you designed the whole program, but from the theory, you can not change the content pointed by "const void *", because it may point to a block memory in the ROM, or whatever.

OK, after talk about "const", let's back to your question. I think you have three methods to do,

1, Keep evil. free((void *)key). As you said, it's evil.

2, Change your logic. A key in a table is just a key, it's used to index the table, it should not own the memory ownership. So beside the key, you should keep a "void *" pointer some elsewhere, and free on that pointer instead of key. However, you may not want to use this method if you allocate a new memory for each key, that will end up with double amount of pointers.

3, OK you are using C not C++, but it doesn't prevent you from thinking in OOP way.
Change "key" to void *, but never use it directly. Instead write a getter function,
const void * getTableKey(MyTable).
And use the getter to access it. Edited by wqking
0

Share this post


Link to post
Share on other sites
[quote name='Lauris Kaplinski' timestamp='1353103816' post='5001652']
The semantics of your key and value is that they are mutable, just not in arbitrary ways. You can free them but not modify them otherwise.
Thus the "evil" part is declaring them "void const *" - not casting them to "void *" in free().

But usually you do not worry about such things in C. It is not perfectly type-safe language and was never intended to be. Thus whatever works and is closest to the actual semantics (without inventing too many hacks) is usually the best.
[/quote]

Ah, I see, you are right that C is not very type safe. I guess the best thing to do is to write error-free code as much as possible.

[quote name='wqking' timestamp='1353140232' post='5001713']
The type of your key, const void *, implicitly means that you should not free it. It points to a block of memory which is not writable, while "free" will destroy that memory, they are conflicting with each other.

You know you can free the key because you designed the whole program, but from the theory, you can not change the content pointed by "const void *", because it may point to a block memory in the ROM, or whatever.
[/quote]

I am not sure on the "not writable" and "read only" part. I think const is just used to tell the compiler "Hey compiler, I don't want this value modified by my code. If you see my code modify this value, treat that as an error!". So it's more like a compile-time error-checking tool to allow the programmer catch his/her own logic mistakes. Well, that's only my guess, I haven't bothered to verify it yet.

[quote name='wqking' timestamp='1353140232' post='5001713']
Change your logic. A key in a table is just a key, it's used to index the table, it should not own the memory ownership. So beside the key, you should keep a "void *" pointer some elsewhere, and free on that pointer instead of key. However, you may not want to use this method if you allocate a new memory for each key, that will end up with double amount of pointers.
[/quote]

Yeah, I make copies of the key. I think oop is the better way.
0

Share this post


Link to post
Share on other sites
[quote name='Lauris Kaplinski' timestamp='1353103816' post='5001652']
The semantics of your key and value is that they are mutable, just not in arbitrary ways. You can free them but not modify them otherwise.
Thus the "evil" part is declaring them "void const *" - not casting them to "void *" in free().

But usually you do not worry about such things in C. It is not perfectly type-safe language and was never intended to be. Thus whatever works and is closest to the actual semantics (without inventing too many hacks) is usually the best.
[/quote]

Ah, I see, you are right that C is not very type safe. I guess the best thing to do is to write error-free code as much as possible.

[quote name='wqking' timestamp='1353140232' post='5001713']
The type of your key, const void *, implicitly means that you should not free it. It points to a block of memory which is not writable, while "free" will destroy that memory, they are conflicting with each other.

You know you can free the key because you designed the whole program, but from the theory, you can not change the content pointed by "const void *", because it may point to a block memory in the ROM, or whatever.
[/quote]

I am not sure on the "not writable" and "read only" part. I think const is just used to tell the compiler "Hey compiler, I don't want this value modified by my code. If you see my code modify this value, treat that as an error!". So it's more like a compile-time error-checking tool to allow the programmer catch his/her own logic mistakes. Well, that's only my guess, I haven't bothered to verify it yet.

[quote name='wqking' timestamp='1353140232' post='5001713']
Change your logic. A key in a table is just a key, it's used to index the table, it should not own the memory ownership. So beside the key, you should keep a "void *" pointer some elsewhere, and free on that pointer instead of key. However, you may not want to use this method if you allocate a new memory for each key, that will end up with double amount of pointers.
[/quote]

Yeah, I make copies of the key. I think oop is the better way.
0

Share this post


Link to post
Share on other sites
[quote name='ultramailman' timestamp='1353143134' post='5001719']
I am not sure on the "not writable" and "read only" part. I think const is just used to tell the compiler "Hey compiler, I don't want this value modified by my code. If you see my code modify this value, treat that as an error!". So it's more like a compile-time error-checking tool to allow the programmer catch his/her own logic mistakes. Well, that's only my guess, I haven't bothered to verify it yet.
[/quote]
I'm not quite sure about the history, but don't forget that C was invented to write OS and system software.
So it's possible that a pointer in C is pointing to a block of memory in the ROM, which is really read only.
Of course you are correct that "const" is used for compile time check, what I want to say is that a const pointer may really point to something that's not writable.
0

Share this post


Link to post
Share on other sites
Don't you have to recast to non const inorder to free.

From what I remember in C, you only free what you allocate with calloc/malloc. Did you allocate memory? If not then just set the pointer to this struct to zero and be done with it. If you made these pointers global then this will not work because you are using singletons, and is considered bad practice. Remember globals are not on the stack they are defined, so make certain no to make const pointers global unless you intend to use it through the life of the entire program. If you did allocate memory then recast to non const and then free.

Personally I would rethink the logic and come up with a system of internal checks and ballances that prevent modification of pointers without using const.
0

Share this post


Link to post
Share on other sites
[quote name='wqking' timestamp='1353144206' post='5001721']
[quote name='ultramailman' timestamp='1353143134' post='5001719']
I am not sure on the "not writable" and "read only" part. I think const is just used to tell the compiler "Hey compiler, I don't want this value modified by my code. If you see my code modify this value, treat that as an error!". So it's more like a compile-time error-checking tool to allow the programmer catch his/her own logic mistakes. Well, that's only my guess, I haven't bothered to verify it yet.
[/quote]
I'm not quite sure about the history, but don't forget that C was invented to write OS and system software.
So it's possible that a pointer in C is pointing to a block of memory in the ROM, which is really read only.
Of course you are correct that "const" is used for compile time check, what I want to say is that a const pointer may really point to something that's not writable.
[/quote]

I see. When you say ROM, what is the degree of the ROM-ness? Is it some region of ROM on the RAM or is it some "harder" kind of ROMs like the EEPROM in which the BIOS reside in? My question probably sounds stupid, but I am not very knowledgeable on this ;o

[quote name='kd7tck' timestamp='1353192758' post='5001870']
Don't you have to recast to non const inorder to free.

From what I remember in C, you only free what you allocate with calloc/malloc. Did you allocate memory? If not then just set the pointer to this struct to zero and be done with it. If you made these pointers global then this will not work because you are using singletons, and is considered bad practice. Remember globals are not on the stack they are defined, so make certain no to make const pointers global unless you intend to use it through the life of the entire program. If you did allocate memory then recast to non const and then free.

Personally I would rethink the logic and come up with a system of internal checks and ballances that prevent modification of pointers without using const.
[/quote]

Oh yes, they are all malloced. I make sure to do a copy of whatever is passed in, so key and val will point to malloced memory. That way I won't accidently free them while the table still has a pointer to them. And no globals are involved here, although I guess anything that is malloced is global, in a way.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0