Jump to content

  • Log In with Google      Sign In   
  • Create Account

Juliean

Member Since 29 Jun 2010
Offline Last Active Today, 08:13 AM

Posts I've Made

In Topic: Overall Strategy For Move-Semantics? [C++11]

26 July 2016 - 04:12 PM

Are people really in the habit of moving every single time they don't need a variable anymore? Unless you're in the habit of doing that, option 4 is totally opaque and you wouldn't know to take advantage of it without reading the implementation. I think that's kind of in line with what Kylotan was saying.


For me, using move semantics in the context of this is somewhat equivalent to using reserve on a collection class like vector. I just get some efficiency for a little bit of additional thinking/design overhead. So yes, whenever possible (in places where it can matter) I tend to move expensive temporaries (like string, vector, ...). However this mostly means that I adjusted my design. IE, where you would usually see something like this:
Foo foo;std::string& string = foo.GetString();string = "Test";string.append("whatever");
Or something along those lines, I would instead do:
std::string string = "Test";string.append("whatever");Foo foo(std::move(string));
I find the latter much cleaner, especially in non-fabriacted examples :D Obviously you could have done this before without the move-semantics, but it would have most likely invoked a copy operation for the content of the string.

EDIT: i think i misread your question. Anybody who is actively using C++11 surely has at least a basic understanding of how and when to use move-semantics. Anyone else wouldn't have that knowledge, so its probably a matter of who you target.

In Topic: Overall Strategy For Move-Semantics? [C++11]

21 July 2016 - 04:03 PM

The games I've worked on that needed unique references for types also needed them to be predictable across builds and across platforms, as they're used for serialization, network messaging, etc. Sadly it appears that type_info::hash_code is 'implementation-defined and may vary between executions of the same program' which makes it unusable, hence there usually being an in-house solution instead. Can't comment on variants - I rarely encounter them these days in C++.

 

Yeah, hash_code isn't even guaranteed to return an unique value for different types in one run. While thats a normal thing for an hash function, it could still be a problem.

 

Having required a type system for my needs, I have come up with a unique solution, which gives arbitrary integer ids to types at runtime, but allows serialization via a fixed name value.

 

Also turns out that I'm using a variant-like class in my code for everything reflection-relation and the like. Its maybe not the best solution for everything (ie. storing variable values for my script system in an array of variant-instances is not the best idea). However for certain stuff it allows for a neat interface, which for me makes it viable at least in a few instances.


In Topic: Finding that balance between optimization and legibility.

18 July 2016 - 08:30 AM

2) Eliminate all branches (even if it means more calculations)

 

Except when the calculations actually outweight the cost of a mispredicted branch... right? I'm not sure on the details, but shouldn't this misprediction cost be something like ~100 cycles on modern desktop CPUs? So if you can skip calculations that take significantly longer than that, a branch is the better choice.

 

Also on desktop, branches that are easy to predict have very little cost. Like something that checks for an memory allocation error that when thrown will terminate the program, the branch will always be false anyways so the only cost should be the branching operation itself. Thats different on consoles where there is no branch prediction (I don't think the current generation added it, did they?), but I didn't program on consoles myself so far so I can't say much about it.


In Topic: Overall Strategy For Move-Semantics? [C++11]

18 July 2016 - 08:24 AM

Option 4 looks a bit messy since it implies the caller has to think about this problem. I'd probably prefer to use option 2, migrating there from option 1 as and when profiles are showing the copies to be expensive. But it depends a lot on whether you're writing new code or maintaining old code, and whether you can assume everyone using the code will understand all the performance implications.

 

True, the caller having to think about it is something that I didn't really see. I'm not sure I'd agree that its really that messy, since it allows the user not to think about it in the general case, and if they eigther measure that its a performance problem or are overly paranoid, they can just add std::move().

 

Its mostly about me using my own code, though. Its a mixture of maintaining old code and writing new one  (since my codebase is now ~3 years old and is still being extended, though I also do heavy refactoring with stuff like this here). So I think outside of my plugin-API, the user having to think about when to apply move is not much different to the writer of the function since its the same person, so I guess I'll stick with option 4, though I see that option 1/2 might be beneficial for a widely used API.

 

However, const-ref for when copies aren't needed, and pass-by-value when copies are needed are technically the correct way. My only "problem" with it is that it prevents me from forward-declaring classes (since pass-by-value requires the full class definition).

 

Ah, true, thats something I didn't see. Now in most of my use cases it doesn't matter because I'm using STL/templated classes here, which means they are included in the header anyways. Outside of that, I will mostly store the moved variables as class members anyways, so yet another reason why their definition is already included in the header. Still a good catch and something I might look out for at times (I'm not a fan of scrapping forward declarations myself).


In Topic: Overall Strategy For Move-Semantics? [C++11]

15 July 2016 - 04:38 AM

Ah, I quess universal references is option 5) then. Though I really do not like this option in the cases I'm discussing here, since this would mean adding templates to a whole lot of functions, with all the downsides bitmaster already mentioned. I'm already using them in some places where it makes sense, but I think I'll stick to 4) when going for a broad-scale solution.

 

If you'd prefer not to have templates then i'd go with the multiple functions with overloads. it's cleaner for calling code:

 

That is one of the reasons why I disliked option 3), however as I've written 4) also has this property, without requiring additional overloads. Also imagine if I had a function like this:

void SetExtentionData(const std::wstring& stExtention, std::string&& stData, ExtentionData::VariableMap&& mAttributes);

In this case I've already accounted for what is likely to be moveable and what not, but if I wanted it to be generic, I had to write 9 different overloads to account for all different semantic attribute combinations (which is why I don't like 2) very much eighter).


PARTNERS