Advertisement Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

1410 Excellent

About Enigma

  • Rank
  1. Enigma


    You have an open parenthesis ('(') on line 4 instead of an open brace ('{').
  2. Why is it that you "don't like using reinterpret_cast" but are happy using a union cast? Although both will undoubtably work in any environment you can envisage, the union cast is technically undefined behaviour (by implication) whereas reinterpret_cast is designed for exactly the kind of thing you are doing and (I believe) guaranteed to work (assuming you are casting float to int and back again with no intermediate operations). Σnigma
  3. Enigma

    stl vector memory problem

    To try and expand a bit on the tutorial, a visitor gets its value from the variant via the boost::apply_visitor function. boost::apply_visitor takes a visitor and a variant and internally calls the appropriate visitor function depending on the type currently held in the variant. To try and illustrate (note, this is not at all how the actual implementation works, I'm just trying to help you understand the usage): #include <iostream> // A really rubbish int/float variant class variant { public: variant(int value) : int_value_(value), float_value_(0.0f), is_int_(true) { } variant(float value) : int_value_(0), float_value_(value), is_int_(false) { } int int_value() const { return int_value_; } float float_value() const { return float_value_; } bool is_int() const { return is_int_; } private: int int_value_; float float_value_; bool is_int_; }; struct visitor { // this is the function called by apply_visitor when the variant // contains an int. The parameter 'value' is the value of the // variant void operator()(int value) const { std::cout << "int " << value << '\n'; } // this is the function called by apply_visitor when the variant // contains a float. The parameter 'value' is the value of the // variant void operator()(float value) const { std::cout << "float " << value << '\n'; } }; void apply_visitor(visitor const & visitor_to_apply, variant & variant_to_visit) { // call the appropriate member function of visitor depending on // the type in variant_to_visit (in a really rubbish way) if (variant_to_visit.is_int()) { visitor_to_apply(variant_to_visit.int_value()); } else { visitor_to_apply(variant_to_visit.float_value()); } } int main() { variant v1(3); variant v2(7.0f); apply_visitor(visitor(), v1); apply_visitor(visitor(), v2); } Obviously boost::variant is far more sophisticated in its implementation. Σnigma
  4. What, no unordered_set? Dictionary Profiling Test Test: Name of the test used Setup: Time taken to setup the data structure in ms Lookup: Time taken to search all of the test words in ms Fail: A count of the number of words encountered that did not exist in the data structure Success: A count of the number of words encountered that were successfully found in the data structure Bytes used: Bytes allocated for the data structure and its testing class MSVC 2008 Release Testing 82368 words (~1000 misspelled, ~1000 gibberish), 25 times Test Setup Lookup Fail Success Bytes used ------------------------------------------------------------------------------- Set 109 1781 1935 80433 3536312 Vector 62 1500 1935 80433 2580840 Vector/vector 47 1219 1935 80433 2946456 Trie (simple) 94 922 1935 80433 16558952 Trie (map) 156 1859 1935 80433 9812716 UnorderedSet 78 578 1935 80433 2965148
  5. Enigma

    stl vector memory problem

    Your Value type is unsafe. It does not implement proper copy semantics and leaks memory. The constructors new[] memory but nothing delete[]s it and if you copy a value both the original and copy will point to the same memory, so changes to one will affect the other. This means it does not meet the requirements for value types in a std::vector. You need to give your Value type a copy constructor (which allocates memory and deep copies the value) and copy-assignment operator (which deletes and allocates memory and deep copies the value) and make the destructor delete[] the memory. In the long term may I suggest you investigate some of the concepts presented here (this might be pretty heavy, so don't worry about digesting it all in one go, and feel free to ask questions): #include <iostream> // C++ comes with a stack implementation #include <stack> // boost ( is a very useful set of libraries // I consider it a must-have for serious C++ coding #include <boost/utility.hpp> #include <boost/variant.hpp> // define your error codes int const ICE_PARSE_STACK_SUCCESS = 0; int const ICE_PARSE_STACK_FAILURE_CORRUPT_STACK = 1; int const ICE_PARSE_STACK_FAILURE_WRONG_FORMAT = 2; // create some types for your memory index and table index struct memory_index { unsigned int value_; }; struct table_index { unsigned int value_; }; // create a typedef to replace your value class // boost::variant is a datatype that holds exactly one of its listed types // at any time. See typedef boost::variant< int, float, memory_index, table_index > value; // to access the value in a variant you apply a visitor // this visitor is for retrieving an int value from the visitor class retrieve_int_stack_value : // we inherit from boost::static_visitor< int > // so that boost's implementation knows that this // visitor returns an int (our error code) public boost::static_visitor< int > { public: // we'll store the value we extract from the stack // into value, so we store a reference to it here retrieve_int_stack_value(int & value) : value_(value) { } // these functions are called by boost's implementation // to retrieve a value from the variant. In this case // the variant stored an int and we want an int, so we // simply perform an assignment int operator()(int value) const { value_ = value; return ICE_PARSE_STACK_SUCCESS; } // the variant contains a float and we want an int int operator()(float value) const { value_ = static_cast< int >(value); return ICE_PARSE_STACK_SUCCESS; } // the variant contains a memory_index and we want an // int int operator()(memory_index) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } // the variant contains a table_index and we want an // int int operator()(table_index) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } private: int & value_; }; // the version for retrieving a float class retrieve_float_stack_value : public boost::static_visitor< int > { public: retrieve_float_stack_value(float & value) : value_(value) { } int operator()(int value) const { value_ = static_cast< float >(value); return ICE_PARSE_STACK_SUCCESS; } int operator()(float value) const { value_ = value; return ICE_PARSE_STACK_SUCCESS; } int operator()(memory_index) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } int operator()(table_index) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } private: float & value_; }; // the version for retrieving a memory_index class retrieve_memory_index_stack_value : public boost::static_visitor< int > { public: retrieve_memory_index_stack_value(memory_index & value) : value_(value) { } int operator()(int) const { return ICE_PARSE_STACK_FAILURE_WRONG_FORMAT; } int operator()(float) const { return ICE_PARSE_STACK_FAILURE_WRONG_FORMAT; } int operator()(memory_index) const { return ICE_PARSE_STACK_FAILURE_WRONG_FORMAT; } int operator()(table_index) const { return ICE_PARSE_STACK_FAILURE_WRONG_FORMAT; } private: memory_index & value_; }; // the version for retrieving a table_index class retrieve_table_index_stack_value : public boost::static_visitor< int > { public: retrieve_table_index_stack_value(table_index & value) : value_(value) { } int operator()(int) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } int operator()(float) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } int operator()(memory_index) const { return ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } int operator()(table_index value) const { value_ = value; return ICE_PARSE_STACK_SUCCESS; } private: table_index & value_; }; // a common technique - depending on the type we want to read // we need to use different visitors, so define a bunch of overloaded // functions that return visitors of the appropriate types retrieve_int_stack_value retrieve_stack_value(int & value) { return retrieve_int_stack_value(value); } retrieve_float_stack_value retrieve_stack_value(float & value) { return retrieve_float_stack_value(value); } retrieve_memory_index_stack_value retrieve_stack_value(memory_index & value) { return retrieve_memory_index_stack_value(value); } retrieve_table_index_stack_value retrieve_stack_value(table_index & value) { return retrieve_table_index_stack_value(value); } // a class for parsing a stack // we make this non-copyable to avoid accidently storing a copy of the // stack parser and parsing the same stack with multiple parsers class stack_parser : boost::noncopyable { public: stack_parser(std::stack< value > & stack) : stack_(stack), error_(ICE_PARSE_STACK_SUCCESS) { } // a template member function which takes a reference to a // type and, if the stack is not empty and no error has // occured, retrieves the value from the top of the stack // using boost::apply_visitor. It returns a reference // to itself so we can retrieve multiple values quickly and // easily template < typename type > stack_parser & operator()(type & value) { if (!stack_.empty() && error_ == ICE_PARSE_STACK_SUCCESS) { error_ = boost::apply_visitor(retrieve_stack_value(value),; stack_.pop(); } else if (error_ == ICE_PARSE_STACK_SUCCESS) { error_ = ICE_PARSE_STACK_FAILURE_CORRUPT_STACK; } return *this; } int error_code() const { return error_; } private: std::stack< value > & stack_; int error_; }; int main() { std::stack< value > stack; stack.push(value(55)); stack.push(value(1234.567f)); int int_value; float float_value; // rather than using error-prone varargs we create a stack parser // and retrieve values via successive applications of operator() //int error_code = IceExtension::ParseStack("fi", stack, &float_value, &int_value); int error_code = stack_parser(stack)(float_value)(int_value).error_code(); std::cout << int_value << ' ' << float_value << '\n'; }
  6. Enigma

    Trouble compiling multiple C++ files

    Inclusion guards will not help in this situation. Inclusion guards only prevent multiple definitions within a single translation unit (cpp file and accompanying includes), they cannot prevent multiple definitions across multiple translation units. Did you read the article Zahlman linked to?
  7. Enigma

    C++ Tip : Treating a Vector as an Array

    The original version of the C++ standard did not require vector to store objects in contiguous memory. This was fixed in TC1. Here's the defect report. In fact I'm pretty sure that this entire post is (probably indirectly) a rip from something written by Sutter, Meyers or another of that crowd. Also note that you must also guarantee that the vector is not empty before applying this technique.
  8. The primary reason to prefer C++ streams over C file IO is type safety. Using C-style file IO the caller is responsible for ensuring that the number and type of all descriptors and arguments match. Any errors results in undefined behaviour. There are also potential security concerns when dealing with strings passed from external sources. C++ streams have none of these problems - it is impossible to mismatch a type or number of arguments. Unfortunately C++ streams can be unwieldly for output which is why some people prefer boost::format which arguably provides the best of both worlds (albeit at a performance penalty). Σnigma
  9. // a function void func() { } // an object int i; // a pointer to a function void (*fp)() = func; // a pointer to an object int * p = &i; // a reference to a function void (&fr)() = func; // a reference to an object int & r = i; // error - fpr is a reference to pointer, func decays to an rvalue of // type void (*)(), rvalues cannot be bound to references to non-const // void (*&fpr)() = func; // error - pr is a reference to a pointer, &i is an rvalue of type int *, // rvalues cannot be bound to references to non-const // int * & pr = &i; // a reference to a const pointer void (* const & fpcr)() = func; // a reference to a const object int * const & pcr = &i;Hopefully you can now see the solution to your problem. Σnigma
  10. Enigma

    Memory leak help - Resolved

    Here's a first pass at clearing it up: // a function for calculating the next highest power of two unsigned int next_power_of_two(unsigned int value) { unsigned int power_of_two = 1; while (power_of_two < value) { power_of_two <<= 1; } return power_of_two; } // prefer to use std::string for text - memory ownership is clearer and there // is no possibility of passing a null pointer // pass by const reference to avoid a copy // I've left the return type as is since I have no context // I would usually prefer to return by value or smart-pointer modelTexture_t * CUtility::LoadPCXTexture(std::string const & filename) { // don't declare variables until just before you need them, // preferably not until you can properly initialise them // using auto_ptr ensures that we can't leak thisTexture // it essentially performs a delete whenever we return from this // function unless we explicitly release it. std::auto_ptr< modelTexture_t > thisTexture(new modelTexture_t()); // as fpsgamer pointed out, it's not possible for thisTexture to be null, // so testing for nullness is redundant // load the PCX file into the texture struct PCXHEADER texInfo; // header of texture thisTexture->data = LoadPCXFile(filename, &texInfo); if (thisTexture->data.empty()) { return NULL; } // store the texture information thisTexture->palette = texInfo.palette; thisTexture->width = texInfo.xMax - texInfo.xMin + 1; thisTexture->height = texInfo.yMax - texInfo.yMin + 1; // allocate memory for the unscaled data // like auto_ptr, vector ensures we can't leak this memory std::vector< unsigned char > unscaledData(thisTexture->width*thisTexture->height*4); // store the unscaled data via the palette // use unsigned types for values that should never be negative for (unsigned int j = 0; j < thisTexture->height; j++) { for (unsigned int i = 0; i < thisTexture->width; i++) { unscaledData[4*(j*thisTexture->width+i)+0] = (unsigned char)thisTexture->palette[3*thisTexture->data[j*thisTexture->width+i]+0]; unscaledData[4*(j*thisTexture->width+i)+1] = (unsigned char)thisTexture->palette[3*thisTexture->data[j*thisTexture->width+i]+1]; unscaledData[4*(j*thisTexture->width+i)+2] = (unsigned char)thisTexture->palette[3*thisTexture->data[j*thisTexture->width+i]+2]; unscaledData[4*(j*thisTexture->width+i)+3] = (unsigned char)255; } } // break repeated functionality out into functions // did you mean to transpose width and height? thisTexture->scaledHeight = next_power_of_two(thisTexture->width); thisTexture->scaledWidth = next_power_of_two(thisTexture->height); // reallocate memory for the texture data // again, use vector thisTexture->data.resize(thisTexture->scaledWidth*thisTexture->scaledHeight*4); // use the GL utility library to scale the texture to the unscaled dimensions gluScaleImage (GL_RGBA, thisTexture->width, thisTexture->height, GL_UNSIGNED_BYTE, &unscaledData[0], thisTexture->scaledWidth, thisTexture->scaledHeight, GL_UNSIGNED_BYTE, &thisTexture->data[0]); // #### OLD MEM LEAK PROBLEM WHEN REFERENCING unscaledData with auto_ptr. return thisTexture.release(); } Your latest code contained an error because you used the scalar form of delete (delete x;) to delete memory allocated with the array form of new (new y[z];). You must always match scalar new with scalar delete (x = new y; delete x;) and array new with array delete (x = new y[z];delete[] x;). Or, even better, avoid explicit invocations of new and delete altogether, as demonstrated above. Σnigma
  11. Enigma

    Numbers to Letters algorithm

    std::string identifier(std::size_t count) { std::string letters = "abcdefghijklmnopqrstuvwxyz"; std::string result; while (true) { result = letters.substr(count % 26, 1) + result; count /= 26; if (!count) { break; } --count; } return result; } I just so happened to need the same thing myself a week ago. Σnigma
  12. XMLNode *readXML(const char *file) { std::ifstream file_stream(file, std::ios::binary); std::istreambuf_iterator< char > begin(file_stream); std::istreambuf_iterator< char > end; std::vector< char > data(begin, end); std::auto_ptr< XMLNode > root(new XMLNode("root")); populateObj(root,data,nb); return root.release(); } Σnigma
  13. Enigma

    Memory leak help - Resolved

    Quite right, I missed that. (I also inadvertantly deleted one too many lines at the top - the declaration of texInfo is still required, albeit not until one line later). Σnigma
  14. Enigma

    Memory leak help - Resolved

    Why are you using malloc in what is clearly C++ code? modelTexture_t *CUtility::LoadPCXTexture(char *filename) { // allocate memory for texture struct std::auto_ptr< modelTexture_t > thisTexture(new modelTexture_t()); if (thisTexture == NULL) return NULL; // load the PCX file into the texture struct thisTexture->data = LoadPCXFile(filename, &texInfo); if (thisTexture->data == NULL) { return NULL; } // store the texture information thisTexture->palette = texInfo.palette; thisTexture->width = texInfo.xMax - texInfo.xMin ; thisTexture->height = texInfo.yMax - texInfo.yMin ; // allocate memory for the unscaled data std::vector< unsigned char > unscaledData((thisTexture->width*thisTexture->height)*4); There, all memory leaks eliminated. Σnigma
  15. Enigma

    Combining line segments

    Quote:Original post by ApochPiQ Only one problem with your rewrite - it doesn't properly handle segments that are oriented in opposite directions. For instance, (0,0)-(1,0) should combine with (2,0)-(1,0) because they are colinear, but since you do a comparison of the sign rather than the absolute value of the sign, these cases will be missed. Once your code is updated to handle that particular edge case, it's effectively isomorphic to mine.(0,0)-(1,0) dx = 1 dy = 0 (2,0)-(1,0) other_dx = -1 other_dy = 0 ((1 == -1 && 0 == 0) || (1 == 1 && 0 == 0)) == true I agree that our code should be exactly equivalent, but given that they were written from scratch by two different people it gives you a point of differentiation. If they both produce the same output it would strongly imply the error lies in the inputs, if they produce different output then at least one algorithm is incorrect and they can be piecewise compared to discover the difference. Σnigma
  • Advertisement

Important Information

By using, you agree to our community Guidelines, Terms of Use, and Privacy Policy. is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!