Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Strange C++ error: ISO C++ forbids declaration of 'player' with no type

This thread is locked; no one can reply to it. rss feed Print
 1   2   3 
Strange C++ error: ISO C++ forbids declaration of 'player' with no type
Ariesnl
Member #2,902
November 2002
avatar

When I make such mistakes it's usually time for coffee ;D

- Wisdom is the art of using knowledge
- String theory: There's music in everything

Dustin Dettmer
Member #3,935
October 2003
avatar

What about copy constructors, using the class in STL list types, getting the class on the stack? All of these are lost (and / or become bug prone) if you start doing junk like this.

bamccaig
Member #7,536
July 2006
avatar

Nicol Bolas
Member #9,238
November 2007

Quote:

What about copy constructors, using the class in STL list types, getting the class on the stack? All of these are lost (and / or become bug prone) if you start doing junk like this.

On copy constructors, how does Pimpl interfere with them? Observe:

1struct SomethingData;
2 
3class Something
4{
5public:
6 Something(const Something &theOther);
7 
8private:
9 SomethingData *m_pData;
10};
11 
12//in the .cpp file:
13 
14Something::Something(const Something &theOther)
15 m_pData(new SomethingData(theOther.m_pData);
16{
17}

It is a simple matter of invoking the copy constructor for the implementation class/struct. Just as you would for any data member held in a pointer.

Personally, I work with everything by pointer. Rather, by boost::shared_ptr. This is because I would rather code than debug memory leaks. So I rarely have need to invoke a copy constructor for most classes.

As long as the class has a functioning copy constructor, you can use it in an STL container quite reasonably. As for putting it on the stack, what is stopping you?

Dustin Dettmer
Member #3,935
October 2003
avatar

Nicol said:

As for putting it on the stack, what is stopping you?

Whenever you use the word 'new' you're not on the stack anymore.

Nicol said:

As long as the class has a functioning copy constructor, you can use it in an STL container quite reasonably.

You're code has three visible compiler errors but I'll give you the benefit of the doubt. On second thought it wouldn't be so bad making copy constructors. It is a lot more work since the default copy constructor wont work and you'll need to make a second CC for SomethingData. Additionally accessing members now becomes more of a hassle.

I don't like it at all. I am a big fan of automatic copy constructors which this Pimpl thing ruins.

Nicol Bolas
Member #9,238
November 2007

Quote:

Whenever you use the word 'new' you're not on the stack anymore.

The object itself would be on the stack; its true contents would not.

I would also like to point out that for games, most objects are not suitable for stack objects. Some objects are, like utility classes; matrices, vectors, etc. But objects of significant importance like images, entities, sounds, GUI windows, and so forth are not appropriate stack objects.

So I would suggest that the need to put all of the memory of such objects on the stack is not so great in most cases.

Quote:

I am a big fan of automatic copy constructors which this Pimpl thing ruins.

I'm quite the opposite: I do not like it when any object is copied, because it takes up performance. Often needlessly. I pass just about everything by smart pointer or const&.

I wait in breathless anticipation for C++0x and it's "move constructor" &&.

Dustin Dettmer
Member #3,935
October 2003
avatar

Nicol said:

The object itself would be on the stack; its true contents would not.

What is a class but a collection of its contents?

Nicol said:

So I would suggest that the need to put all of the memory of such objects on the stack is not so great in most cases.

We disagree here. I like putting as much on the stack as I can (with the exception of killing your stack limit).

Nicol Bolas
Member #9,238
November 2007

Quote:

What is a class but a collection of its contents?

The class being on the stack means that it will be automatically destroyed. So long as the constructors allocate memory, and the destructors deallocate memory correctly, you have 0 memory leaks. It is always better to wrap a bare pointer in some kind of object, whether a Pimpl class, shared_ptr, or something else.

Dustin Dettmer
Member #3,935
October 2003
avatar

Nicol said:

The class being on the stack means that it will be automatically destroyed.

It also means its placed in prime high-speed memory and it removes any malloc / free overhead.

Nicol Bolas
Member #9,238
November 2007

Quote:

It also means its placed in prime high-speed memory and it removes any malloc / free overhead.

Copy constructor overhead will kill performance a lot faster than not being in stack memory. The copy constructor for every STL container will perform at least one memory allocation, so you lose any of the malloc/free advantage.

Dustin Dettmer
Member #3,935
October 2003
avatar

Nicol said:

Copy constructor overhead will kill performance a lot faster than not being in stack memory.

Pimpl has exactly the same issues in this scenario, only they're exaggerated and worse.

Nicol said:

The copy constructor for every STL container will perform at least one memory allocation, so you lose any of the malloc/free advantage.

Pimpl will have twice as many allocations...

I feel like we're going in circles here. Are you sure you know what you're talking about?

Nicol Bolas
Member #9,238
November 2007

Quote:

Pimpl has exactly the same issues in this scenario, only they're exaggerated and worse.

I'm afraid you have misunderstood my point.

If you use stack objects directly and nearly exclusively, your code will necessarily pass objects by value more frequently than code that uses pointers or other forms of references often. I previously stated that my style of programming does not use the copy constructor at all for most objects. By passing objects by reference as a matter of course, I avoid any unintentional copy operations. That means that your code will use the copy constructor more frequently than mine.

As an example, std::vector is often maligned for its brutal performance when resizing a vector. It must copy all of its elements to a new location when it resizes itself. After doing so, it will destroy the initial array.

Under your programming style, a list of entities would be stored in a std::vector<Entity>If vector<Entity> needs to reallocate its memory, it will provoke the copy constructor on a number of Entity objects, then destroy the originals. If your Entity object stores a lot of other objects, like a list of BITMAPs, SAMPLEs, or other things, each of them will need to be copied using the Allegro or otherwise API. These are not fast operations and all of them will involve memory allocation. The destructor will have to delete these objects as well.

In my case, I would store a std::vector<boost::shared_ptr<Entity> >, which is a much lighter-weight class. Even though my Entity class would be Pimpl-ed, and a deep-copy constructor would cause an extra allocation, no such operation happens in this case. The shared_ptr class's copy constructor copies the internal pointer and bumps a reference count. The destructor decrements a reference counter. The previous increment of the counter guarantees that the reference count will not hit zero and provoke an actual destructor.

Another point. If the allocation overhead for the interface class ever becomes onerous, I can always override operator new/delete on the class to use an pool allocator. The size of the interface class will always be the size of one pointer if it has no virtual members. This makes memory allocation time nil for all practical purposes.

I think your problem with Pimpl stems from your personal unwillingness to use references or pointers. You have designed a specific style of coding around this limitation. The problem isn't that Pimpl is bad; the problem is that you should not use the rest of your coding style with Pimpl. Just like a C programmer working in C++ should not pretend that classes do not exist.

Dustin Dettmer
Member #3,935
October 2003
avatar

Nicol said:

That means that your code will use the copy constructor more frequently than mine.

Unrelated concept. Making a total guess, I probably use references more than you do and therefore the copy constructor less than you do.

Nicol said:

In my case, I would store a std::vector<boost::shared_ptr<Entity> > ...

Nicol said:

I can always override operator new/delete on the class to use an pool allocator.

All unrelated concepts. You have yet to explain a concept (besides Pimpl) that I do not already understand.

Nicol said:

I think your problem with Pimpl stems from your personal unwillingness to use references or pointers. You have designed a specific style of coding around this limitation. The problem isn't that Pimpl is bad; the problem is that you should not use the rest of your coding style with Pimpl. Just like a C programmer working in C++ should not pretend that classes do not exist.

I think your problem is lack of experience. Go bad and learn all the corner details of C++ you skipped over and come back. When you have arguments for Pimpl that actually address Pimpl and not completely erroneous side-tracks I'll listen to what you have to say.

Nicol Bolas
Member #9,238
November 2007

Again there seems to be some miscommunication. Allow me to return to the beginning.

You pointed out that a Pimpl class cannot "be put on the stack" because its true contents are not on the stack. The contents are not in "prime high-speed memory" that "removes any malloc / free overhead".

This is not true on several levels.

If you have a class:

class NotOnTheStack
{
private:
  std::vector<Something> m_notStack;
};

The actual list contents of m_notStack are exactly as named: they are not on the stack. If you store any kind of STL container in a class, the true contents of that container are not in "prime high-speed memory", nor does it "remove any malloc / free overhead". The STL class will still allocate memory on the heap.

Some might even say that class NotOnTheStack is very similar to a Pimpl'd class.

The only way you can get a list on the stack is to make it a static list, like this:

class OnTheStack
{
private:
  Something m_stackVar[20];
};

So not Pimpl'ing a class is no guarantee of avoiding malloc/free overhead. The only way to do so is to only ever use static lists. This limits the flexibility of a design.

Another problem is that stack memory is not "prime high-speed memory" at all. It is just memory, no different from heap memory.

What stack memory is is more likely to be cached. But even that has its limits. If you put a large object on the stack, you will likely be using parts of the stack that are not in the cache.

The likelihood of the stack to be cached also depends on how much the stack is used. If you use a very small stack, it will not take up much room in the cache. This leaves plenty of room for frequently accessed objects.

If you use a lot of stack memory, it will likely be cached. If you use little stack memory, you have more cache room for heap memory. The cache works for the code either way; it will store whatever it is that you frequently use. But stack memory itself is not faster by the virtue of being stack memory.

I would also like to take this opportunity to point out the following: Pimpl is not something I invented. It is in use in the world. It is not exactly common, but it is far from rare to see code employ Pimpl. FreeType, a C library, uses Pimpl. Allegro uses a degree of Pimpl by hiding implementation details of an object behind a driver. And the new Allegro API will go further than that. Others have mentioned that KDE, one of the two desktop systems for Linux, employs Pimpl.

What I'm saying is that there are a lot of lines of Pimpl'd code that gets used every day. Pimpl does not need to be proven or supported. It has a track record that speaks for itself.

You don't have to use it or even like it. I didn't much care for it until I worked on a project with so many header inclusions that it took an hour to recompile just for touching certain header files. But you should respect it as a valuable tool for solving programming problems.

Dustin Dettmer
Member #3,935
October 2003
avatar

I disrespect it because it is not a valuable tool for my paradigms, as well as many wonderful C++ features.

Quote:

Another problem is that stack memory is not "prime high-speed memory" at all. It is just memory, no different from heap memory.

Clearly you do not fully understand the programming concepts we are discussing. I see no reason to continue this discussion.

HoHo
Member #4,534
April 2004
avatar

Quote:

I disrespect it because it is not a valuable tool for my paradigms, as well as many wonderful C++ features.

It is a tool that has its uses. If you don't think you need it then fine, don't use it. Just don't think that it doesn't have any use what so ever.

Quote:

Clearly you do not fully understand the programming concepts we are discussing.

Stack is just more likely to be cached as it lives in the same area where code does, that is all the difference there is. Once the data is cached there is no speed difference what so ever.

Also as Neil pointed out, most STL objects don't have their data in stack anyway.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Dustin Dettmer
Member #3,935
October 2003
avatar

HoHo said:

Stack is just more likely to be cached as it lives in the same area where code does ...

We are in agreement.

HoHo said:

Once the data is cached there is no speed difference what so ever.

It's getting to the cache that is an issue for heap memory.

HoHo
Member #4,534
April 2004
avatar

I'm just wondering, has anyone actually made some real-life benchmark on stack vs heap data. Sure, initial loading will be much slower for heap but if your variables are used frequently they'll be in caches for most of the time anyway and if they are not used frequently then the slowdown they cause is insignificant.

Just think of Pimpl as a way to trade very little runtime performance for great compile time speedups.

How much classes are stored in heap anyways, most stuff lives in containers and they are certainly not in heap. I tried to think of a few examples but for my current program there are almost no heap classes at all, at least not the ones that are used often.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

SiegeLord
Member #7,827
October 2006
avatar

Quote:

Just think of Pimpl as a way to trade very little runtime performance, arbitrary inheritance, clean code, public members, templates etc, for great compile time speedups.

Fixed.

No matter what benefits, it still is a horrible mess that is hard to work with.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]

HoHo
Member #4,534
April 2004
avatar

Quote:

No matter what benefits, it still is a horrible mess that is hard to work with.

So, have you actually tried using it?

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Nicol Bolas
Member #9,238
November 2007

Quote:

I disrespect it because it is not a valuable tool for my paradigms

That sounds rather arrogant. The fact that a tool is not valuable for your paradigms does not mean that it is not valuable period, and thus not deserving of respect.

It is also deeply shortseighted. If a tool is not valuable for your code currently, that does not mean it will not be in the future.

Ignoring a tool because you can't use it yet simply means that if you need it, you will be unprepared to use it or prejudiced against using it.

Quote:

Clearly you do not fully understand the programming concepts we are discussing.

I could just as easily suggest that you do not understand the concepts of CPU caching and memory architecture. I did just show that the stack is not "prime high-speed memory". This renders your position against Pimpl to be nothing more than your own personal biases towards certain C++ features and against others.

Quote:

I'm just wondering, has anyone actually made some real-life benchmark on stack vs heap data.

There really is no need. It is all just memory in the end.

Quote:

Stack is just more likely to be cached as it lives in the same area where code does

I should probably point out that this is not true. At all.

The stack is not a special piece of memory; it is memory just like the heap. It does not "live in the code" at all. It lives in the same virtual address space as the heap, though stack memory addresses are often far away from heap memory addresses.

The stack, just like the heap, is stored in the cache when it is used, and forced out of the cache if something else with a "similar" memory address is used more often. This is a simplification, but it is enough for now.

If you allocate 1MB of stack space, and you only use the first 32KB of it, the first access into the upper areas of that stack space will still be a cache miss. To put it bluntly, there is nothing special about the stack; allocating large swaths of it will not guarantee that the memory is cached. The only thing that will make that guarantee is the use of the memory.

So if you throw 50 Entity objects onto the stack, each 1KB in size, this will not guarantee that they are all in the cache. It will be no different from heap allocating 50 Entity objects. The only thing that will cause them to be cached is using the particular memory addresses.

The cache does not care about the stack. If you use the same heap memory a lot, you will find that it is in the cache often. If you use the same stack memory a lot, you will find that it is in the cache often. If you use some of one and some of another, you will find that what you often use is in the cache often. That is how a cache works.

Quote:

Just think of Pimpl as a way to trade very little runtime performance, arbitrary inheritance, clean code, public members, templates etc, for great compile time speedups.

Most of theses are debatable points. What is considered "clean code" is certainly a matter of opinion.

In my experience, "clean code" is code whose functionality is obvious from the code itself, code that is self-contained, without touching unrelated systems needlessly, and code that is virtually impossible to use incorrectly without hitting exceptions, asserts, or the like. Public members for 99% of classes are clearly not clean. Arbitrary inheritance is also out: code that is meant to be inherited will be easy to inherit from, and code that isn't will make it difficult/impossible to do so. Templates can certainly be used, and they can even be used in complex classes in accord with Pimpl. So long as the implementation class is not templated.

So, to me, Pimpl is perfectly clean, and the idea of using public members/arbitrary inheritance for most data is very much against that form of cleanliness.

Dustin Dettmer
Member #3,935
October 2003
avatar

You have a very silly religion-esk style of arguing. To improve your point you surround it with unrelated points and you believe this somehow makes your argument stronger.

What does me and my level of arrogance have to do with any of this?

I find your conversational skills annoying.

Nicol Bolas
Member #9,238
November 2007

Quote:

To improve your point you surround it with unrelated points and you believe this somehow makes your argument stronger.

If these points were unrelated, then I would suggest that you actually show how they are unrelated. All you have done to date is claim that they are unrelated. This despite the clear fact that you yourself brought up the idea of the stack being fast memory compared to the heap.

Thus far, you have made two claims against my arguments: that they are either presenting an unrelated point or that I "do not fully understand the programming concepts we are discussing." Neither of these comments have any support. They are simply stated as though they are facts.

So please demonstrate that I don't know what I'm talking about or that I am introducing irrelevant information. Otherwise, please refrain from making baseless accusations of ignorance or irrelevance.

Dustin Dettmer
Member #3,935
October 2003
avatar

Here is your first paragraph, separated into two chunks.

Nicol, part 1 said:

If these points were unrelated, then I would suggest that you actually show how they are unrelated. All you have done to date is claim that they are unrelated.

Nicol, part 2 said:

This despite the clear fact that you yourself brought up the idea of the stack being fast memory compared to the heap.

Now here is a quote from my last post.

I, repeating myself, said:

To improve your point you surround it with unrelated points and you believe this somehow makes your argument stronger.

An exercise for the reader: Why would I post this quote again?

Moving on, the burden is on you to make logical arguments that are logical and follow proper flow. You can easily demonstrate that you do not use this cheap trick by refraining from doing the cheap trick. Clearly, this is too hard for you.

Nicol said:

please demonstrate that I don't know what I'm talking about

I would ask you to please demonstrate that you know what you're talking about but to be honest I think your response would be a boring post to read, so I wont.

edfredcoder
Member #7,985
November 2006
avatar

I really don't understand why my simple question spawned this big argument.

 1   2   3 


Go to: