It's a lost cause: there's no such thing as "sane" or "orthodox" C++. Instead, use something actually sane like Go. Or Rust, if you really must (first bad pun is free, then it's 50 cents each).
If you're gonna bother with orthodox C++, or Go (suited to 3d games? nobody seems to have tried or lived to tell the tale), or Rust (no libraries anyway, so you may as well use something which wraps C easily and is higher level), why not try Nim?
Show HN: Crown – A flexible game engine written from scratch in C++
101–110 of 179 posts
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#102Earlier quoted context omitted.
Generally speaking many C++ game engines avoid the STL stuff and reimplement their own more predictable containers, often with custom allocation schemes. The engine at the last game company i worked at, for example, had its own containers and memory allocator and allowed you to define the allocation category and pool per allocator and per object class (so, e.g., dynamic strings would be isolated to their own pool to…
> Generally speaking many C++ game engines avoid the STL stuff and reimplement their own more predictable containers This seems a little like cargo cultism. I wonder if any of these shops regularly measure the performance of their custom containers and compare with the standard library on a modern optimizing compiler and make a reasoned judgment that it's still currently worth the trade-offs to stick with their own s…
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#103Earlier quoted context omitted.
What's wrong with using templates vigorously?
Some things that are not so nice about templates: - dozens to hundreds of compiler error lines for a single error, where it's hard to find out what the real problem is (IDEs often point to the wrong line) - Code is hard to follow. E.g. try to figure out from boost asio source code which code is actually used if if you do a async_read(socket). I personally gave up after the second level of template substitutions, and…
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#104It's a lost cause: there's no such thing as "sane" or "orthodox" C++. Instead, use something actually sane like Go. Or Rust, if you really must (first bad pun is free, then it's 50 cents each).
sane like Go Yet Go uses the oh-so-error-prone return value error checking that has been so successful in C :/
try:
...
except: passRe: Show HN: Crown – A flexible game engine written from scratch in C++
#105Earlier quoted context omitted.
Generally speaking many C++ game engines avoid the STL stuff and reimplement their own more predictable containers, often with custom allocation schemes. The engine at the last game company i worked at, for example, had its own containers and memory allocator and allowed you to define the allocation category and pool per allocator and per object class (so, e.g., dynamic strings would be isolated to their own pool to…
> Generally speaking many C++ game engines avoid the STL stuff and reimplement their own more predictable containers This seems a little like cargo cultism. I wonder if any of these shops regularly measure the performance of their custom containers and compare with the standard library on a modern optimizing compiler and make a reasoned judgment that it's still currently worth the trade-offs to stick with their own s…
Part of it is also for cross-platform consistency. No chance for bugs caused by using a different stdlib, etc. This is worth it when a lot of the toolchains for consoles are arcane have the chicken/egg-ish problem of often having poor stl implementations since they expect everybody to implement their own.
I've been out of game dev for a while though. These days I'd expect using the C++ stdlib to be more common, and mallocs are faster now (although even if you're bundling e.g. jemalloc, I imagine you still get a substantial benefit from using pools or arenas in many cases).
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#106Earlier quoted context omitted.
> Generally speaking many C++ game engines avoid the STL stuff and reimplement their own more predictable containers This seems a little like cargo cultism. I wonder if any of these shops regularly measure the performance of their custom containers and compare with the standard library on a modern optimizing compiler and make a reasoned judgment that it's still currently worth the trade-offs to stick with their own s…
Older implementations of STL had a lot of issues, EA wrote their own version way back when to address them with a list of whys here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n227...
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#107Earlier quoted context omitted.
I don't think this is the proposal. The proposal is that the object contains a genuine constructor that only does the bare-bones "safe" stuff, and then it has a separate non-static method that does the might-fail initialization. So: class Foo { public: Foo(); bool initialize(); // returns success ... }; ... Foo foo; if ( !foo->initialize() ) { // handle error } This also means you can break up your initialization so…
It was almost the exact proposal specified by my grandparent post except using a pointer rather than an optional. It's also a technique that is widely used. See for example the cocos2d-x game library. The benefit of such a technique is that you can then make the constructor private, making it impossible to create an object and not also call the initialize() method.
Using a separate initialize member function means that you may have objects in a zombie state laying around after a failed construction which lead to all kind of initialization order issues (you might get a pointer to the object, but is it initialized?). Also you need to remember to check the return type, which also need to be meaningful (does it return false on failure? or it returns 0 on success?).
Two phase initialization is a known antipattern which is, unfortunately, widely used and lead to all kind of pains.
Friends do not let friends use 2PI.
edit: sorry, I misread your comment, you were referring to the static function returning a pointer, which as you note is almost the same as the optional version. It forces heap allocation though, which is bad.
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#108While I find the "sane C++" approach pragmatic and practical all things considered, I'm firmly in the "time to use a better language if possible" camp. The problem with approaches requiring extra discipline is: it's an extra mental burden to bear while programming. Also, you'll always be limited by the fact that you're working in a less pure ecosystem and will likely end up using libraries written in "not very sane C…
The first step would be to actually define such a subset. And what happens when this subset calls into "full" C++? If you don't want to lose interoperability you have to be pretty conservative with the things you disallow. In particular since C++ kept the C-style preprocessor "just copy and paste that file in there" includes it would be tricky to handle "sane C++" including "full C++", especially since templated C++…
This can probably be solved by adding flexible configuration options (C++ compilers already have plenty). In practice, project leaders would then decide on a set of such options, similar to what happens with code style guidelines.
Perhaps some day a majority of people will agree on a "good" subset of C++ / option set and it will become standardized as a new language or dialect.
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#109Earlier quoted context omitted.
Not quite. Try this: import "os" func main() { os.Open("this file does not exist") } This will compile just fine, producing no compiler error or warnings whatsoever. The error is just silently ignored. Compare to Rust: use std::fs::File; fn main() { File::open("this file does not exist"); } This will produce the following warning: warning: unused result which must be used --> test.rs:14:5 | 14 | File::open("this file…
A slightly related note: you can get similar behavior in C (and C++) with compiler extensions. In GCC and clang marking function with '__attribute__((warn_unused_result))' will produce a warning if function is called without using the result. Equivalent for MSVC is '_Check_return_'. Obviously this is not nearly as convenient as your Rust example, but enables some of its the benefits.
Re: Show HN: Crown – A flexible game engine written from scratch in C++
#110Earlier quoted context omitted.
If you disable exceptions hoe do you handle failures in constructors?
Instead of using a constructor you can use a constructor method e.g.: class Foo { public: static std::optional create(); private: Foo(); };