Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Member Since 08 Aug 2000
Online Last Active Today, 10:57 AM

#5213141 Is this book for C++ ok/valid

Posted by BitMaster on 26 February 2015 - 12:53 PM

Things don't really change in C++, they only add to it, right?

That depends. Old ways of coding still work fine but are considered harmful, e.g. use of NULL instead of nullptr, using raw instead of smart pointers, not making use of C++11 features.

There is also something like std::auto_ptr which has been deprecated since C++11 and currently looks to leave us completely with C++17. Granted, it's the only thing I can think of right now which could be actively removed.

#5211410 What are the recommended places to store save data?

Posted by BitMaster on 18 February 2015 - 06:18 AM

2. app-data: this works, but it was hell to navigate the player to the save games if you need them for bug analysis.

Really? Our support has to deal with some really non-IT people and with some encouragement most of them manage to get '%appdata%\MyDirectory' pasted into their Explorer...

3. my-docs: works better, navigation worked, thought I didn't find a way to share them between different accounts (install as admin, play as xyz)

Shouldn't it be irrelevant if the accounts used for installation and playing were the same? The application should query the relevant directory of the currently logged in user on each startup, not once during installation.

#5211233 What are the recommended places to store save data?

Posted by BitMaster on 17 February 2015 - 12:04 PM

Personally I would consider saving within the application's directory to be incorrect on Windows.

Unless of course you are intentionally offering a portable installation option.

#5211192 javascript weird number bug

Posted by BitMaster on 17 February 2015 - 09:27 AM

My JavaScript knowledge is extremely limited, but I'll hazard a guess:

The number you are trying to work with would require 54 bits to represent. That's well outside the scope of a normal 32 bit integer. Apparently JavaScript then uses a 64 bit floating point variable to represent the number but since it only has 52 bits available (64 minus sign and exponents bits) some number just cannot be represented.

#5210988 LTD: Non-member VS Memeber functions

Posted by BitMaster on 16 February 2015 - 09:46 AM

For that example I would clearly favor two member functions: 'Matrix transposed() const' returns a modified copy while 'void transpose()' modifies the matrix itself.

The closest to a general rule I could think of would be: if it would take a single Class parameter (perhaps with some other non-Class parameters) it's probably better off as a member functions. That rule is just sketched into sand though, not hammered into granite. Generous helpings of common sense and experience are advised.

#5210939 Entity-Component Confusion

Posted by BitMaster on 16 February 2015 - 02:51 AM

I like the Positech guy and own several of his games. However, I'm not going to accept him as any kind of authority for the subtler corners of programming. The last time I was on his blog he was on a bit of a rant regarding std::sort and the fact it's not stable, despite the fact that the conveniently available documentation clearly points that out as the second sentence and link std::stable_sort as well.

#5210510 Variable id mapping

Posted by BitMaster on 13 February 2015 - 10:41 AM

Since this is about a limited number of known types a boost::variant or something similar might be applicable as well.

#5210032 String subscript out of range

Posted by BitMaster on 11 February 2015 - 08:21 AM

If you "Retry" in that dialog the debugger should point you to the exact location where the problem happens. Simply walk up the stack trace until you hit your code.

What most likely happens is that you try to access the i'th character in a string which has less than i characters.

#5208571 Comparison of STL list performance

Posted by BitMaster on 04 February 2015 - 02:08 AM

I have no clue why std::string and std::list even appear in the same sentence here.

They are both sequence containers. I thought they migh have similar implementation. The default std::allocator is the same for all of them, and it can allocate multiple elements at once (using std::allocator::allocate). And I also think that at least when you insert multiple elements, std::list allocates all the memory for them at once. I'm really just making assumptions and drawing conclusions here though, because I'm too lazy to test this. And you guys talk about "specific implementations" as though STL is just some abstraction - but really, it doesn't abstract the memory allocations. It might give you a method to do that by providing your own allocator, but I think OP was interested in the default implementation here.

There is no default implementation. The standard requires that the containers have certain member functions and typedefs. The standard sometimes requires that these member functions have a guaranteed complexity. For example std::list::erase for a single element must be O(1) (that's actually an important property because, as Bregma correctly pointed out it makes your list implementation idea with buckets and no next/prev pointers impossible). Another example is that the storage of an std::vector must be continuous (since C++11, but even before no known standard library implemented that differently).

As long as you do not violate the requirements of the standard you can implement the standard library any way you want (and different standard libraries will be implemented differently). For example many (not all) standard libraries implement small string optimization for std::string (so short strings do not require an allocation).

That said, I'm really not sure where your enthusiasm for trying to optimize std::list is coming from, especially since it sounds you really want an std::deque in the first place.

I wasn't trying to optimize it. I was just trying to answer the OP's original question. I really don't see what deque has to do with everything I said.

Me (and apparently several others) in this thread get the distinct impression you are trying to somehow shoehorn an std::list into an std::deque. I don't see how you can implement a list with the suggestions proposed by you without violating the standard. At the same time the std::deque seems to have all that (and more) right out of the box. 

A std::list that invalidates iterators after erase() or insert(), and does not support remove() and splice() as defined in [], would be non-conforming.

This statement seems a bit out of place. I never said anything about iterators.

No you didn't, and that's part of the problem. You try to look at a small part of a list and modify it according to what you think would be better. But you fail to see that doing so would make other things much more difficult or impossible. A list and its iterators (including their guarantees) cannot be looked at separately.

#5208353 Comparison of STL list performance

Posted by BitMaster on 03 February 2015 - 02:29 AM

I have no clue why std::string and std::list even appear in the same sentence here. While I don't think the standard requires a particular kind of internal storage for an std::string, it needs to support std::string::c_str and storage as anything but a glorified std::vector would be inadvisable (although several std::string implementations do not require allocations for small strings).

That said, I'm really not sure where your enthusiasm for trying to optimize std::list is coming from, especially since it sounds you really want an std::deque in the first place. And while I used to believe (when I was much younger and inexperienced) std::list was a very useful data structure in the past I have found that in actual practical experience it's probably the least used of them all.

#5208024 Resetting std::stringstream to state before read

Posted by BitMaster on 01 February 2015 - 06:28 AM

std::basic_ios::clear() should do the trick.

#5207888 DLL interfacing performance

Posted by BitMaster on 31 January 2015 - 12:10 PM

Personally, I'm a big fan of modularization. However, I would consider actual DLLs as the last alternative for that. Static libraries are almost always doing a much better job with less headache. If you have megabytes of shared code between executables used next to each other, then yes, DLLs might be something for you if it outweighs the problems (see below).

There is no problem using classes across DLL boundaries (extremely important detail: if you know exactly what you are doing). For a start, name mangling across different C++ compilers will in general not be the same. So using C++ code (that's not just about classes, it's about anything not marked as pure C) across different compilers (or even different versions of the same compiler) will not work correctly for the simple reason they cannot find the functions they expect to find. Just because one compiler put an 'int myFunc(char*)' into the DLL does not mean another compiler can even find it. If you build both the DLLs and the executables using it with the same compiler (and the same build settings), you are clear though.

That's one part of the problem. Another problem is that you need to take care about where something was allocated and where it is freed. If the DLL newed something it can hand out that pointer to another DLL or the executable where it can be used. You are not allowed to just free that pointer in another module though. This can be worked around if both modules use a runtime which explicitly allows that (like /MD for MSVC). This is the reason why libraries generally offer a CreateXXX/DestroyXXX pair of functions for XXX you can create. Take note that if the runtime is updated you might have to ensure both executables and DLLs are all rebuilt and deployed using the same version of the runtime. I'm not sure how frequent that is but it happened to me at least once for MSVC 2005 or 2008 and missing an executable or DLL in a deployment can lead to highly annoying and difficult to track down bugs.

As a side effect of the above paragraphs, unless you can make sure you are using the exact same compilers and the exact same build settings standard library containers (including, say, std::string) are usually out for the public DLL interface. I say 'build settings' because that's not just about the runtime library used. For example MSVC allows to configure (among other things) iterator debugging at compile time using defines. If these defines are not identical extremely bad stuff will happen.

In summary, I'd like to reiterate once again: if all you are after is a bit of organization and modularization, forget about DLLs. Static libraries do that job wonderfully without any of the problems. If you really, absolutely need DLL functionality treat carefully and expect problems while you learn the ropes.

#5207544 Efficient way to erase an element from std::vector

Posted by BitMaster on 29 January 2015 - 04:29 PM

That's a classic violation of the Rule of Three (or the newer C++11-counterparts) and it should probably only fulfill std::is_probably_broken.[/size]

Not always. The rule of three says if you have one, you probably should have all three. There are absolutely valid cases for having one-or-more, but not all.
For example, if all the members of your class leverage RAII, there's no need to explicit define a destructor, even if you needed to define a copy constructor or assignment operator (or delete one of the same) because one of the members was a reference or const.

I find it difficult to agree with this statement, probably because I have spent at least one day too much debugging code where the root cause turned out to be a Rule of Three violation after a lot of suffering. I would say in practically all cases where a contained RAII resource is present you do not need to specify any of the three (because the compiler will automatically generate them based on what is already defined or not defined for the RAII resource).

Also, if there is a RAII resource inside the class then it's not going to have a trivial destructor, then the class which contains it won't have that either and my statements were in the larger context of whether a std::is_trivially_destructable would have a real use. I maintain 'no' on that count.
With a bit of creativity I'm sure one could cobble together an actual use case for going against the Rule of Three. But I also believe those are so rare it should lead to more than normal reflection about if it's really okay.

#5207421 Efficient way to erase an element from std::vector

Posted by BitMaster on 29 January 2015 - 07:15 AM

I would disagree. If an object fulfills a theoretical std::is_trivially_destructable but not std::is_trivially_copyable it has non-trivial copy and/or move semantics without a non-trivial destructor. That's a classic violation of the Rule of Three (or the newer C++11-counterparts) and it should probably only fulfill std::is_probably_broken.

#5207403 Efficient way to erase an element from std::vector

Posted by BitMaster on 29 January 2015 - 05:21 AM

Out of curiosity, does anyone know if there is any chance the swap can be optimized to a move when the items don't have destructors?
I guess that could be difficult unless the memory in the vector is actually shrunk..
Not that it should really matter, but for large POD types it seems unnecessary to exchange the memory instead of just copying.

C++11 introduced a POD testing template, so you could write:
if( std::is_pod<T>::value )
  container[index] = container.back();
  std::swap(container[index], container.back());

Wouldn't it be enough to test for std::is_trivially_copyable? Requiring the whole more restrictive POD-property seems unnecessary.