Mxz

Members
  • Content count

    91
  • Joined

  • Last visited

Community Reputation

504 Good

About Mxz

  • Rank
    Member
  1. I have just finished a little sudoku puzzle game. It is my first java game. :) Sudoku Puzzles It has a few different board size options, difficulty levels and a highscore table. Let me know what you think!
  2. If you take Visual Studio 2005 as an example, and the following two code samples as a simple test. Switch statement version int main() { int i = rand() % 5; switch(i) { case 0: i = 0; break; case 1: i = 1; break; case 2: i = 2; break; case 3: i = 3; break; case 4: i = 4; break; case 5: i = 5; break; } std::cout << i; } if-else statement version int main() { int i = rand() % 5; if(i == 0) { i = 0; } else if(i == 1) { i = 1; } else if(i == 2) { i = 2; } else if(i == 3) { i = 3; } else if(i == 4) { i = 4; } else if(i == 5) { i = 5; } std::cout << i; } Under the compiler optimization setting Favor fast code, the following disassembly is produced for the switch statement version. call dword ptr [__imp__rand (4020A8h)] cdq mov ecx,5 idiv eax,ecx cmp edx,ecx ja $LN1+2 (401081h) jmp dword ptr (401094h)[edx*4] $LN6: mov ecx,dword ptr [__imp_std::cout (40203Ch)] xor edx,edx push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret $LN5: mov ecx,dword ptr [__imp_std::cout (40203Ch)] mov edx,1 push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret $LN4: mov ecx,dword ptr [__imp_std::cout (40203Ch)] mov edx,2 push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret $LN3: mov ecx,dword ptr [__imp_std::cout (40203Ch)] mov edx,3 push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret $LN2: mov ecx,dword ptr [__imp_std::cout (40203Ch)] mov edx,4 push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret $LN1: mov edx,ecx mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret lea ecx,[ecx] As you can see, there are just a couple of jumps at the top of the function. However, the same code under the Favor small code optimization setting compiles down to the following. call dword ptr [__imp__rand (4020A8h)] cdq push 5 pop ecx idiv eax,ecx mov eax,edx sub eax,0 je main+37h (401037h) dec eax je main+32h (401032h) dec eax je main+2Dh (40102Dh) dec eax je main+29h (401029h) dec eax je main+25h (401025h) dec eax jne main+39h (401039h) push ecx jmp main+2Fh (40102Fh) push 4 jmp main+2Fh (40102Fh) push 3 jmp main+2Fh (40102Fh) push 2 pop edx jmp main+39h (401039h) xor edx,edx inc edx jmp main+39h (401039h) xor edx,edx mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret On this compiler setting the select statement has been turned into a series of comparisons and jumps. The if statements on the other hand produce the following output when the Favor fast code optimization is set. call dword ptr [__imp__rand (4020A8h)] cdq mov ecx,5 idiv eax,ecx test edx,edx jne main+22h (401022h) mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret cmp edx,1 jne main+37h (401037h) mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret cmp edx,2 jne main+4Ch (40104Ch) mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret cmp edx,3 jne main+61h (401061h) mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret cmp edx,4 jne main+76h (401076h) mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret cmp edx,ecx jne main+7Ch (40107Ch) mov edx,ecx mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret Here we have many comparisons and jumps taking place. The Favor small code setting produces the following out of the if statement. call dword ptr [__imp__rand (4020A8h)] push 5 cdq pop ecx idiv eax,ecx test edx,edx je main+34h (401034h) cmp edx,1 je main+34h (401034h) cmp edx,2 jne main+1Dh (40101Dh) push edx jmp main+33h (401033h) cmp edx,3 jne main+25h (401025h) push edx jmp main+33h (401033h) cmp edx,4 jne main+2Dh (40102Dh) push edx jmp main+33h (401033h) cmp edx,5 jne main+34h (401034h) push edx pop edx mov ecx,dword ptr [__imp_std::cout (40203Ch)] push edx call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] xor eax,eax ret As you can see, for Visual Studio the if statements in this case have been implemented using many jumps under both compiler settings. The select statement was implemented using a jump table when using the favor fast code optimization setting, but was implemented using a series of comparisons and jump statements under the favor small code setting. In short it depends on your compiler, code and compiler settings. It is hard to make general statements about these things. The best way is to profile and see. [Edited by - Mxz on September 10, 2008 1:32:36 AM]
  3. Polymorphic array.

    It is customary to simply store a base class pointer in the array, and use that polymorphically. class Base {}; class One: public Base {}; class Two: public Base {}; std::vector<Base*> Storage; Storage.push_back(new One); Storage.push_back(new Two); Use of a smart pointer would be preferred though.
  4. libcmtd.lib linker errors

    Are you using Multi-threaded (/MT) in the Runtime Library field of the C/C++ Project properties?
  5. In C++ an object is considered to be destroyed as soon as execution enters the destructor. Objects in C++ are also destroyed outside in, and so by the time the base class destructor is called the derived class destructor will already have been called. This means by the time the base class destructor is called your vtable is already wrong. Now if the objects derived class destructor is called in between the ThreadProc thread aquiring the mutex and calling the virtual function, then you will get the error you describe. The locks do not protect that from happening.
  6. To expand a little on the other posts, a pointer is simply a variable which stores a memory address. This stored memory address is typically the location of a variable, but this is not always the case (you can set a pointer to 0 for example, and there is not valid object at the memory address 0). When you compare two pointers, you compare the addresses which are stored in the two pointer variables and NOT the objects at those addresses. int main() { char* pchar = new char; if(array == "Hello") { //... } } In the above code we have tried to compare a character pointer with "Hello". "Hello" is called a string literal. A string literal is a variable of type const char[], that is a const character array. In this example we have a string literal "Hello" which has a type of const char[6]. Arrays have the property that they can be implicitly converted into a pointer to the first element of the array. This means that you can use the name of the array as if it were a pointer which stores the memory location of the first element in the array. As an example, "Hello" can be implicitly converted to a const char pointer which contains the memory address of the character H. With that in mind, it should be a bit clearer as to what is going on in the above example. if(pChar == "Hello") The above line is treated as a comparison between two pointers. The reason for this is that there is no operator== defined in C++ which compares a const char[6] to a char*. The only operator== that can be called is the operator== which has a prototype of bool operator==(T* ParameterOne, T* ParameterTwo) Where both parameters are of the same type. Since pChar is a char* and our string literal "Hello" is a const char[6] which has an implicit conversion to both const char* and char*, the operator== with the following prototype is called. #1 bool operator==(char* ParameterOne, char* ParamterTwo) The above prototype, as mentioned before, simply compares the memory addresses stored in the two pointer variables. In the case of pChar, this will be the address returned from the call to new char. In the case of our string literal "Hello", the const char[6] will be implicitly converted to a pointer to the first character of the array, namely a pointer which stores the memory address of the letter H. Clearly the address of letter H and the address returned from our call to new char are different, and so the comparison returns false. Your case is slightly different in that the pChar is pointing to a dynamic array rather than just a dynamic char. #include<cstring> int main() { char* pChar = new char[6]; std::strcpy(pChar, "Hello"); if(pChar == "Hello") { //.. } } This is exactly the same as the previous example, as you are still comparing a variable of type char* with a const char[6], which can only result in the comparison operator for two pointers being called. Clearly pChar will point to the memory address returned from new char[6], which in this case also now happens to be the location of a character array containing the word Hello. Our string literal is still a const char[6] which has an implicit conversion to char* and so the operator== stated in the earlier example is called. It is important to realize that the const char[6] of the string literal and the char[6] returned from our call to new char[6] are completely different objects with completely different memory addresses, and so pointers to them can never be equal. Clearly this pointer comparison is not what you intended, you merely wanted to compare the two arrays that the pointers point to, and not the addresses of there first elements. To do this for character arrays, there is a function called strcmp. The correct code would then be #include<cstring> int main() { char* pChar = new char[6]; std::strcpy(pChar, "Hello"); if(std::strcmp(pChar, "Hello") == 0) { //Two strings are equal } } The functions strcpy and strcmp are inherited from C. Now C++ provides a much neater way of going about this. The C++ standard Library contains a string object which encapsulates much of what you are trying to do. It also makes use of operator overloading to provide a more natural interface for dealing with strings. The above code, for example, can be replaced with the equivalent C++ code of #include<string> int main() { std::string One = "Hello"; if(One == "Hello") { //Two strings are equal } } In the above code, the constructor for the std::string encapsulates the previous examples calls to new char[6] and to std::strcpy. The operator== for an std::string and a const char* is overloaded to encapsulate the call to std::strcmp. The main advantages of using std::string instead of explicitly using strcpy and strcmp yourself are: It handles all memory management for you - you do not have to worry about using new and delete to allocate the string, this is all handled for you. It allows you to do the same thing in much fewer lines of code It makes your code more readable It makes you more productive For a full list of the functions supported by std::string, you should consider buying a reference book like The C++ Standard Library by Josuttis. #1 - (NOTE the conversion from const TYPE[] to TYPE* applies only to string literals, const int[6] cannot be implicitly converted to type int*, though you could convert it explicitly).
  7. Passing Variable question

    There is also an interesting article relating to typedefs of pointers here. Worth a read. [smile]
  8. Passing Variable question

    Pointers are variables which store a memory address. Pointers also carry some additional type information about what is contained at the memory address which it is storing, whether it be an integer, constant integer or a float. So, for example, a pointer to an integer stores a memory address of an integer. int* pInteger = new int; //... Dereferencing the pointer to the integer will yield the integer stored at the memory address which is contained within the pointer variable. *pInteger = 10; The above code dereferences the pointer to integer, which yields the integer at that address, and then assigns 10 to that integer. If the pointer to integer was a pointer to constant integer, the above assignment would fail. const int* pInteger = new const int; *pInteger = 10; //error In the above code, the pointer now points to a constant integer, and so dereferencing the pointer now yields a constant integer, which obviously cannot be assigned to, as it is constant. Thus the above example will not compile. However, the pointer variable is not constant, so you can still change the value stored inside the pointer variable so that it contains the address of another constant integer. const int* pInteger = new const int; delete pInteger; pInteger = new const int; The above code demonstrates that. Sometimes you may wish the value contained in a pointer to be unchangeable, and like any other variable, you can make a pointer constant as well. This is not to be confused with the above examples where it was the variable which the pointer pointed to which was constant. Constant pointers are created in the manner shown in your code. int* const pInteger = new int; delete pInteger; pInteger = new int; //error In the above example, we created a constant pointer to an integer with the address of a dynamically allocated integer. We then tried to assign another integer variables address to our constant pointer. The code fails to compile, as you cannot assign to a constant pointer once it has been created. So the answer to your question, the const qualifier makes the pointer constant, and not the variable at the address which it stores. We can also have constant pointers to constant integers, like so. const int* const pInteger = new const int;
  9. Quote:Original post by Troll To help me out next time, how was my post confusing? As far as I can see there's only one time I mentioned static but didn't mention namespace. It didn't look confusing to me. The part I thought may have confused people was the very first thing you said, namely. Quote: static variables are deprecated
  10. Quote:Original post by Troll Quote:Original post by Mxz static variables at namespace scope are deprecated in C++. const variables have internal linkage by default. You can verify this with the following code. static variables are deprecated, but that's irrelevant for two reasons: 1) They're deprecated in favor of, of all things, globals. Namespace-scoped statics are deprecated in favor of globals in unnamed namespaces. They're fairly (but not completely) identical. 2) Even without #1, they'll never be removed because they're too prevalent in pre-existing code. I'm a big fan of namespace-level statics or #1 now that they are deprecated. They're much preferable to a private class static. If it's a private static, it's an implementation detail, and I'd rather not change a header file when I change an implementation detail. I don't think you are correct to say that a deprecated feature will never be removed, for the very reason that the definition of the word deprecated in C++ is: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions. If they had no intention of removing it then they would not have made it deprecated, but if you wish to carry on using it, that is your prerogative. I think it is also worth stating explicitly that use of the static keyword is only deprecated when declaring objects in namespace scope, your post seemed to confuse that slightly. However, I do agree that static namespace scoped variables being deprecated is largely irrelevant to this discussion (assuming that is what you meant). I used it merely as an example of why the static keyword is not needed to give a variable internal linkage, and hence give the translation unit conceptual ownership of that 'global' variable.
  11. Quote:Original post by Anonymous Poster Quote:Original post by Mxz That depends on what you mean by global, it is perfectly possible for a variable in the global namespace to be 'owned' by a particular translation unit, you simply need to give it internal linkage. *** Source Snippet Removed *** Clearly the variable global is owned by my.cpp in this case. Similarly you can imitate a primitive form of private global data which can be 'owned' by a particular translation unit in the following manner. I don't think that's doing what you think it's doing. I can still extern const int global; class MyPrivateClass { /* ... */ }; extern MyPrivateClass GlobalInstance; in any file to access it (cf. header files). What you need is static const int global; or, to follow the C++ idiom namespace { const int global; } These will create "private globals" in a less primitive way. No, I was correct. static variables at namespace scope are deprecated in C++. const variables have internal linkage by default. You can verify this with the following code. my.cpp const int i = 10; myother.cpp extern const int i; int main() { int j = i; } Which fails to compile with an unresolved external symbol. As to your other example, yes you can do that, but then you can do similar things to break any of C++s encapsulation features. I'm not sure what your point is there.
  12. Quote:Original post by Oluseyi Quote:Original post by simon10k pros: Less function passing. That's not actually a pro. It means that you can not trivially track access to the data, which is a huge con. The problem with globals is one of ownership/responsibility. Since no module or piece of code explicitly owns it, "everything" owns it - which is a recipe for potentially very ugly code. That depends on what you mean by global, it is perfectly possible for a variable in the global namespace to be 'owned' by a particular translation unit, you simply need to give it internal linkage. //my.cpp const int global = 10; Clearly the variable global is owned by my.cpp in this case. Similarly you can imitate a primitive form of private global data which can be 'owned' by a particular translation unit in the following manner. //my.cpp class MyPrivateClass { //... }; MyPrivateClass GlobalInstance; Here only my.cpp has access to the MyPrivateClass definition, and so you could say that my.cpp owns the global variable GlobalInstance.
  13. Another interesting example of why the implicit conversion to const char* from a string class can cause subtle problems is the following. #include<cstddef> #include<cassert> class string { public: static const unsigned int buffer_size = 200; char& operator[](unsigned int index) { assert(index < buffer_size); return buffer_[index]; } private: char buffer_[buffer_size]; }; int main() { string example; example[0] = 'a'; } Here we simply want to initialize the first letter of a fixed size string with the letter a. The code is fine, the string class has an overloaded operator[] which takes an unsigned integral type. We are calling that function with a signed integer literal (0), which has a standard conversion available to an unsigned integer, and so the function can be called after our signed integer undergoes this conversion. However, if we then add an implicit conversion to a const char* to our string class, like so. #include<cstddef> #include<cassert> class string { public: static const unsigned int buffer_size = 200; char& operator[](unsigned int index) { assert(index < buffer_size); return buffer_[index]; } operator const char*() { return buffer_; } private: char buffer_[buffer_size]; }; int main() { string example; example[0] = 'a'; } The code now fails to compile. The reason for this is that we have introduced another potential candidate for the call to an operator[], namely that of the operator[] applied to a const char*. The example string can now be converted to a const char* through our user defined conversion, and the operator[] can be called on that pointer without any further conversions. In addition, we have our original operator[] which can be called if the signed integer literal 0 is converted to an unsigned integer. So we have two potential candidates available which both require one implicit conversion, so we have an ambiguity. This can be solved in two ways, one would be to change our strings operator[] to take a signed int as an indexing parameter, like so class string { //... char& operator[](int index) { return buffer_[index]; } }; No implicit conversion is now required to call this operator with a signed int, and so there is no ambiguity with a signed int. But we have now introduced an ambiguity with an unsigned int. If the user then tries to do something like the following, the code will again fail to compile. #include<cstddef> #include<cassert> class string { public: static const int buffer_size = 200; char& operator[](int index) { assert(index < buffer_size); return buffer_[index]; } operator const char*() { return buffer_; } private: char buffer_[buffer_size]; }; int main() { string example; for(unsigned int iter = 0; iter < 200; ++iter) { example[iter] = 'a'; } } Here an implicit conversion is required to call both the const char* operator[] and our example strings operator[], namely the conversion from string to const char* and the conversion from int to unsigned int. The solution to this would be to provide overloaded operator[] functions which take all possible indexing types as parameter, be it int, unsigned int, short int, unsigned short int, char, unsigned char or unsigned long int. class string { public: char& operator[](unsigned int index); char& operator[](int index); char& operator[](unsigned short int index); char& operator[](short int index); char& operator[](unsigned char index); char& operator[](unsigned long int index); private: char buffer_[buffer_size]; } That should remove most ambiguities, but is far from ideal. You would also need the const member function counter parts of those functions so that they can be called on a constant string instance. Quite an interesting and subtle problem though.
  14. D3D Device Creating Problem

    It is difficult to help you with your current description, or lack there-of. In order to get the most helpful replies, you might consider posting the following. A more detailed description of what the problem is What do you mean by you are having trouble? You cannot get the code to compile? You have no code? The code throws an exception? A description of what language and tools you are using Are you using C++, C#, VB? Post any code you currently have Without this basic information, it is impossible to help you.
  15. Arrays and Pointers

    Quote:Original post by TEUTON I know it's being said that arrays are not equal to pointers and every good programmer would know that. I guess I am not a good programmer. So please enlighten me by telling the difference between them. You are correct in claiming that arrays and pointers are not equal. An array is a contiguous series of elements in memory. A pointer is a variable which stores a memory address. Arrays and pointers do share some links though. An array can decay into a pointer to the first element There is an implicit conversion from an 'array of N elements of type T' to a pointer of type T. This allows for code like the following, which results in the variable parray containing the memory address of the first element of the array of 10 integers. int array[10]; int* parray = array; A more common use of this might be string literals, which are simply arrays of const chars. const char* parray = "Hello"; Here the string literal "Hello" is of type const char [6], and so has an implicit conversion, or decay, into a pointer of type const char*. The subscript operator behaves equally for both arrays and pointers When you invoke the [] operator on an array or a pointer, like so E1[E2] The result is equal to the following statement *(E1 + E2) This requirement means that E1[E2] results in the same value independent of whether E1 is an array or E1 is a pointer to the first element of the same array. If that is not obvious then perhaps it is clearer when you consider the following fragment again. *(E1 + E2) The only way this expression can be valid if E1 is an array is if E1 decays to a pointer to the first element through the previously mentioned implicit conversion. In which case, you end up with the same result as if E1 was a pointer to begin with (i.e. *(pointer + E2)) A slightly less abstract example might be int array[10]; array[9] = 10; //*(array + 9) = 10; Conversely, the above definitions also allow for the commonly known obfuscation whereby the indexing integer is outside the subscript operator, and the array or pointer is within the subscript operator (i.e. E2 is the pointer or array and E1 is the indexing integer or enumeration). This is demonstrated by the following code. int array[10]; 9[array] = 10; //*(9 + array ) = 10; These requirements are also what allows for the use of dynamic arrays like the following. int* pointer = new int[10]; pointer[9] = 10; //*(pointer + 9) = 10; 9[pointer] = 10; //*(9 + pointer) = 10; delete [] pointer; Although there are these similarities, it is important to note that pointers and arrays are completely different types and concepts in C++. Pointers can be, and often are, used completely outside the domain of arrays.