Live data from Hacker News

Show HN: Crown – A flexible game engine written from scratch in C++

github.com

171–179 of 179 posts

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#171
post #126

Earlier quoted context omitted.

> It forces heap allocation though, which is bad. It does, and it can be, but in situations where it matters, the static create function typically returns a value from a preallocated pool of memory, so objects are all contiguous and cache friendly.

Even when using a pool allocator, you still have unnecessary indirections which is expensive. One of the benefits of C++ is the ability of being able to allocate subobjects inline with the containing object or array. By forcing indirection, allocating subobjects requires navigating a potentially deeply nested tree.

This is true, and like I said above, it's not a method I prefer to use, it's just something that is commonly seen in projects that disable exceptions in order to avoid 2 phase initialization.

There are definitely things to be aware of before adopting such a pattern, or when trying to optimize code that uses it.

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#172
post #104

Earlier quoted context omitted.

sane like Go Yet Go uses the oh-so-error-prone return value error checking that has been so successful in C :/

Still better than try: ... except: pass

Hah! It could be worse... imagine your example, but in Java with checked exceptions ;)

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#173
post #116

Earlier quoted context omitted.

It is very different from having a static method returning an optional, which guarantees that you can access the optional (with at least an assert in debug mode) only if the object is actually successfully constructed. 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…

I agree that 2PI leads to all kinds of pain, but what I meant is not 2PI. Here's a more complete example: class Foo { public: static Foo* create() { Foo* result = new Foo(); //exceptions disabled so new can return nullptr if ( result ) { //configure result here } return result; } private: Foo() {} }; ... Foo* badFoo = new Foo(); // compiler error because Foo() is private Foo* foo = Foo::create(); //all good, no 2PI a…

That still means you can't creat instances of Foo on the stack though, doesn't it? Or you can't have a storage or contiguous Foo's (e.g. vector)

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#174
post #116

Earlier quoted context omitted.

I agree that 2PI leads to all kinds of pain, but what I meant is not 2PI. Here's a more complete example: class Foo { public: static Foo* create() { Foo* result = new Foo(); //exceptions disabled so new can return nullptr if ( result ) { //configure result here } return result; } private: Foo() {} }; ... Foo* badFoo = new Foo(); // compiler error because Foo() is private Foo* foo = Foo::create(); //all good, no 2PI a…

That still means you can't creat instances of Foo on the stack though, doesn't it? Or you can't have a storage or contiguous Foo's (e.g. vector )

Correct. It means you can't create instances of Foo on the stack (outside of the Foo class).

You can have contiguous Foos, but not in a vector. You can either have another static function to return an array of Foos, or more commonly have some sort of pool allocator and have the create function allocate objects from the pool.

Anyway, yes, there are limitations for using this pattern, so like all things it's a matter of weighing up the tradeoffs.

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#175
post #99

Earlier quoted context omitted.

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.

It is very different from having a static method returning an optional, which guarantees that you can access the optional (with at least an assert in debug mode) only if the object is actually successfully constructed. 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…

There are lots of cases out there where the so-called "zombie" state is a perfectly valid one, and may for various reasons be preferable to representing that state externally (for example, with a null pointer). Such an object is simply a placeholder instance of the object that is ready to do work, but not yet actually doing anything. If necessary, it can check its internal state and throw exceptions when not-valid-while-uninitialized methods are called.

The examples that come immediately to mind are the Publiser, Subscriber, and Timer classes that are part of the ROS C++ API: http://docs.ros.org/api/roscpp/html/classros_1_1Publisher.ht...

I agree that there are caveats with it, but I get nervous when people toss around a phrase like "known antipattern" with such confidence.

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#176

The code seems clear enough, though I think the preprocessor macros for wrapping OS specific logic could be at the function level or class level rather than at the statement level.

Why when code amount is small enough?

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#177
post #15

Earlier quoted context omitted.

Would love to hear more about the motivation for this (and other aspects of your C++ usage). I know EA wrote their own implementation of STL[1] to get around the problems that the standard implementation was causing in their game engines. Doing a 'diff' between that and a standard implementation should highlight some of the potential problems they found. [1] https://github.com/electronicarts/EASTL

What is "a standard implementation"?

[deleted]

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#178

Earlier quoted context omitted.

Right, but that was a long long time ago, 64 bits long. Even calling it "STL" nowadays kind of dates someone. I wonder how regularly EA currently does bake-offs between their stuff and the standard library. Not that it would matter at this point--they probably have so much legacy code depending on it that it would be painful to switch.

You can clone the repo and run the benchmarks yourself. When I last did it it was quite mixed (compared to libc++ on a MBP) - a lot of things were the same or slightly faster in EASTL, occasionally some things were an order of magnitude faster, some things an order of magnitude slower. Those were in what I would consider "edge cases" rather than general usage, for which the two were fairly similar. As other comments…

My recollection (which could be wrong, it's been a long time) is that the white papers Microsoft freely distributed for XBox 360 development said specifically to not use any STL containers except contiguous memory ones and probably not those either without custom allocators. The penalties for cache misses/pipeline flushes were very high and naive STL usage made both those things happen a lot in real games (Microsoft would step in and help developers and would do post mortems on things they did to improve performance).

Re: Show HN: Crown – A flexible game engine written from scratch in C++

#179
post #104

Earlier quoted context omitted.

sane like Go Yet Go uses the oh-so-error-prone return value error checking that has been so successful in C :/

Still better than try: ... except: pass

I wouldn't say so. This screams "I am an idiot", missing handling can easily pass unnoticed.
Post reply on HN