|
The simple things are where the hell hides
Can you please tell me why? Pointer is a pointer however you turn it... sure if it is object i
understand the reason, but the question is what is the problem if i use it as pointer? Or rather
the question is understanding...
As far as i understand, the only difference between vector<bla*> and vector<some*> is
in casting on [] or at(). And if "bla" is derived from "some" the cast is not a problem.
btw, concerning casting; i simply cant do it other way, at the point where i am needing the cast
i am asking for i have no idea what type is stored inside, the only thing i do know is what is
base class. i dont want to loose general usage of library and coupling it with like 15 classes
that have nothing to do with it and... well it would be a mess.
(i am sorry, i dont want to be annoying but i am not bible kind of guy (god said; thou shall not
cast vectors) i want to understand what i am doing wrong and why.)
|
|
|
|
|
yeti11 wrote: i dont want to loose general usage of library and coupling it with like 15 classes
that have nothing to do with it and... well it would be a mess.
Not necessarily. You can hide the 15 classes within design patterns based on construction and/or behavior as appropriate to the 15 classes. The example given in Wikipedia is a very common one for a bridge, every object class for computer drawing has a "draw" function, at the far end the draw() is generic, you don't care what is being drawn, the information held within allows you to draw almost any shape and add more shapes.
http://en.wikipedia.org/wiki/Bridge_pattern[^]
look at the C++ code for drawing Circles and Squares from the same "shape" class. Is this the type of generic bridge you are trying to accomplish?
yeti11 wrote: i want to understand what i am doing wrong and why
without actually seeing your code, I can't tell you where the error lies for sure. The design via pointers is dangerous because of the STL habit of automatically changing its memory structure. Also pointers are not always held constant between threads, depending on when the pointers are built, and assigned the memory may not be shared between threaded operation calls.
Which brings us back to generic classes to hide implementation. Bridges or Composites[^] and building with other abstraction classes such as Builder[^]
Take a look through the gang-of-four Design Patterns[^] and see if one of those is what you are trying to achieve.
_________________________
Asu no koto o ieba, tenjo de nezumi ga warau.
Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
|
|
|
|
|
In class constructors all the variables that i want to have (de)serializable are stored in
a form &m_variable (+type) and then stored in dispatch table as void* (!)
When i call serialization over whole class hirarchy, the only thing i have is void* (!) so
if i want to do anything, i NEED to cast it to something.
At the time of serialization, there is nothing that would shrink/grow array.
I have ways of solving it with redesign, thank you everyone for trying to help, but if i
would want that, i would already do it. Unfortunaly no one is talking about the question;
What is wrong with casting vector holding pointers?
I'll try to reexplain my point; if vector is holding pointers to whatever, it can be casted
as nothing is changed internally (look on template as on freaking macro). in any case holding
WHATEVER pointer, the internal storage per "record" is size of pointer (, address, 4 bytes on
32 bit machine, in memory it is the same).
Please can someone think about what i am saying?
(multithreading is far outside this topic, the problem is not thread related)
|
|
|
|
|
yeti11 wrote: What is wrong with casting vector holding pointers?
Nothing, "per se" the problem with pointers is it is simply easier to make "unsafe code" which means the chances of a small bug like this one, are increased significantly above other alternatives. The reason for the alternatives is that you can spend a week tracking down this one bug, or another one, simply because the pointers give you the freedom to shoot yourself in the foot. It isn't the pointers fault really, a pointer is simply power, of course there is the ultimate power phrase, which applies to other pointer problems, but not this one. This is why you hear so many people say "no pointers, don't do this" and it isn't because it "cannot be done" it is because "the chances increase for error." You spend more time debugging than you do writing the code, time/money lost, etc. That is the primary reason to avoid pointers.
You can eventually figure this out, and we can all toss you out a hundred "small" errors that could be causing the problem. You'd probably get twice the number of suggestions from running something like PC-Lint on the code. Eventually one will be right. You find it, fix it, and all is okay. But the reason why folks are discouraging the pointer use, is because of the great number of "little" things that can go wrong.
We don't know your code, you do. You can't post all of your code, from the idea of IP and also space, so all any of us can do is generalize, offer some suggestions. But the primary reason folks are telling you to avoid the pointers is because it just increases the chance for these bugs. Generally speaking there is absolutely nothing wrong with pointers, pointers are good, pointers are powerful, and good written code with pointers works very well. It's just harder to get there, or find problems like this.
I've written programs with pointers, I've multi-threaded pointers, I have done near every great thing in the book with pointers. I have also made every mistake in the book with pointers. I use alternatives as often as possible, even in multi-object node storage, such as graphical scene graphs, which are my business.
Obviously I am not helping, so I will wish you well. I hope you find it and soon. Good luck in this and everything else.
Jeff
_________________________
Asu no koto o ieba, tenjo de nezumi ga warau.
Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
|
|
|
|
|
yeti11 wrote: Can you please tell me why? Pointer is a pointer however you turn it... sure if it is object i
understand the reason, but the question is what is the problem if i use it as pointer? Or rather
the question is understanding...
Sure a pointer is a pointer but the object it points to is not altered by casting the pointer. Consider the following:
#include <iostream>
class CClass1
{
public:
CClass1() : m_Data(0) {}
int m_Data;
};
class CClass2
{
public:
CClass2() : m_pData("Hello") {}
const char* m_pData;
};
void main()
{
using namespace std;
CClass2 c2;
CClass1 *pOne = reinterpret_cast<CClass1*>(&c2);
cout << pOne->m_Data << endl;
}
This program will not behave as expected. The cast from CClass2* to CClass1* does not change the CClass2 into a CClass1 ; it just changes the type of the pointer. So the compiler thinks that pOne points to an object of type CClass1 but it actually points to a CClass2 instance.
Steve
|
|
|
|
|
It's not that simple. The following program while perverse compiles and runs just fine and works as expected:
#include <iostream>
#include <vector>
class CBase
{
public:
virtual void Print() { std::cout << "CBase" << std::endl; }
};
class CDerived : public CBase
{
public:
virtual void Print() { std::cout << "CDerived" << std::endl; }
};
int main(int argc, char* argv[])
{
typedef std::vector<CBase*> BVec_t;
typedef std::vector<CDerived*> DVec_t;
DVec_t dvec;
dvec.push_back(new CDerived);
BVec_t &bvec = *reinterpret_cast<BVec_t*>(&dvec);
CBase *pBase = bvec.front();
pBase->Print();
delete pBase;
return 0;
}
Like I said in my previous post; it's possible in some instances but perverse and not necessary. Also it only works because the memory layouts of both classes happen to be the same, an explicit specialisation could change this (like std::vector<bool> ).
Steve
|
|
|
|
|
Ok... Stephen Hewitt as from the start, you are moving to my direction, something like this is what i have.
I am talking explicitly about vector<something*> as i am handling all other types differently.
Well thank you, it didnt help me solve the problem but it did help me to abandon the idea that something is
wrong with cast (unless someone will say something that explains why i shouldnt do it).
(i dont know if those "rate" points are helpfull to you but anyway i will give you 5 for both posts)
|
|
|
|
|
yeti11 wrote: but it did help me to abandon the idea that something is
wrong with cast
Don't abandon this idea; the cast is perverse and is asking for trouble. The troubles you’ll encounter with this type of thing are amongst the hardest to track down. In short, you’re short-circuiting the compiler’s type checking so a whole class of problem that would normally result in compiler errors now result in runtime errors instead. It was not my intention to encourage bad design.
Steve
|
|
|
|
|
"It was not my intention to encourage bad design."
Well, we shall see, i'll gladly post the results here I know it is
hack but it saves so much complications, not to mention that it keeps
code nice and clean, alternative i was thinking about is to do my own
template that would internally store vector<mybase*> but on the
outside casts will be made on [] and at(). Instead of storing pointer
to this "wrapper" template i will store pointer to internal vector and
as internally the type is allways the same, but on the outside it is
still used as it was. In any case this is gonna be firmly tested, if
it fails i'll know.
imho, as far as i can logically think about the cast, there should be nothing
wrong with it. Actually i am casting from vector<dword>* to vector<dword>*
|
|
|
|
|
As I said, in your case it will work. Nevertheless, in general, it is an unforgivable design decision. I’ve also mentioned that template specialisation could also invalidate this construct although the chances of this occurring are fairly slim. If was an employer and one of my employees done this without a bloody good reason I’d fire him on the spot. Naturally their are exception to every rule but in general there is very little places you need to pull this kind of hackery.
Steve
|
|
|
|
|
Damn, do you never sleep?
Ok, ok, lets say you convinced me, i am gonna write freaking templates today (*grumble*),
although i am still pissed of that this should be declared as a hack.
I hate templates and i believe at the end there is allways a good reason not to use them
(speed, redundancy in binary, MESS) but unfortunally this time i was pushed into them as
too much code depending on them to change it. Oh well, its a living
|
|
|
|
|
I think templates kick ass. If you use them right runtime speed is one of the advantages of templates.
Steve
|
|
|
|
|
Yeah i forseened that Well have a nice day/night...
|
|
|
|
|
I have read your post and the answers to it, before posting mine:
1) Do not do that!
2) Do not even think about doing that!
3) If you have to, then redesign it so that it is not required.
Why don’t you just use a virtual base class and store a pointer to that in the vector?
class A
{
public:
A() {}
virtual ~A() { std::cout << "destroying class A" << std::endl; }
virtual print() const { std::cout << "class A" << std::endl; }
};
class B : public A
{
public:
B() {}
virtual ~B() { std::cout << "destroying class B" << std::endl; }
virtual print() const { std::cout << "class B" << std::endl; }
};
int main()
{
std::vector<A*> a_vec;
int i;
for( i=0; i<3; ++i )
a_vec.push_back(new B);
for( i=0; i<3; ++i )
a_vec[i]->print();
for( i=0; i<3; ++i )
delete a_vec[i];
return 0;
}
Then if you need to access a method that is in a derived class that is not defined in the base class, use dynamic_cast . You can check the pointer, returned by the cast, to insure that it is not null, which would indicate that the cast would be invalid.
I hope that helps.
INTP
"Program testing can be used to show the presence of bugs, but never to show their absence."Edsger Dijkstra
|
|
|
|
|
Thank you for the answer, but i would rather point to 1) and 2) WHY?
|
|
|
|
|
Better late than never!
1) It overly complicates a simple operation and any methods available in the base class are also available in the derived class, unless the base class was declared private; in which case I would hope the complier rejects it. The idea is to find the simplest overall solution to a problem, making it easier to understand and implement. Except in a very narrow niche, this type of conversion should be avoided as it can introduce unexpected side effects.
2) Well that was a bit of an over statement. I can see thinking about it, but my mind automatically rejects that line of thought as anything more than a means to better understand the language.
If you need to store pointers to the derived class in a vector, other than a vector of base class pointers, then use dynamic_cast to convert the individual pointers on a per pointer bases, as needed. I do feel though that if you need to do this, then there is a fundamental flaw in the design.
INTP
"Program testing can be used to show the presence of bugs, but never to show their absence."Edsger Dijkstra
|
|
|
|
|
Hello, everyone, I'm a beginner of windows programming. Now I've got a problem on thread.
I wrote the following codes:
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hT1;
hT1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
CloseHandle(hT1);
cout<<"main thread"<
|
|
|
|
|
Firstly, you shouldn't be using CreateThread to start a thread that uses CRT functions. Use _beginthread or _beginthreadex . See this[^] page (near the bottom) for official confirmation on this.
Note that calling CloseHandle on a thread doesn't stop the thread executing.
As for the timing, you can't really make too many assumptions about the thread scheduling, but your result don't surprise me.
Steve
|
|
|
|
|
Thank you a lot, Steve. You comments are really helpful. I need to do more research on it.
One more question: the "thread schedule" you mentioned. do you mean the time when the worker thread is executed is uncertain?
Thank you!
-- modified at 22:39 Sunday 14th January, 2007
Jeffrey
|
|
|
|
|
The scheduling will depend on many things, some of which are:
- The priorities of each thread.
- The number of CPUs (or cores in multi-core CPUs).
- The number of threads in the system.
- The OS.
Steve
|
|
|
|
|
Hmm, looks like I need to go through some OS stuff to make it very clear.
Thank you, Steve!
Jeffrey
|
|
|
|
|
Basically, you shouldn't assume much about the scheduling of threads beyond the simple things such as threads with higher priorities will be run in preference to threads with lower priorities and the scheduler will be “fair” amongst threads with the same priorities. If you need finer control you should use synchronization objects such as CRITICAL_SECTION s and the like.
Steve
|
|
|
|
|
To learn the basics and avoid common pitfalls regarding multithreading, read Joe Newcomer's article on the subject here[^].
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
|
|
|
|
|
wrote: int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hT1;
hT1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
WaitForSingleObject(hT1, INFINITE);CloseHandle(hT1);
cout<<"main thread"<<endl;
return 0;
}<="" blockquote="">
In this way - for example - you let the thread execute and wait for thread to finish, then back in main thread and this will finish, too.
Output will be
thread1
main thread
Nuclear launch detected
|
|
|
|
|
wrote: I expected only "main thread" would be printed out, coz the main thread quits before Thread1 can be executed.
You're still thinking of things as synchronous. Windows, and especially threads, are a fundamentally asynchronous, event-driven universe.
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|