News for hackers. Stuff that matters.
Re:Show HN: Crown – A flexible game engine written from scra... by comstock on Thursday June 22, 2017 @05:34AM (#14611043)
Interesting! I'd be interested in better understanding the motivation behind Orthodox C++. In particular, you seem to dump most of the C++ standard library:

"Don't use anything from STL that allocates memory, unless you don't care about memory management."

I now mostly avoid templatization in my own code unless there's a really good reason. But the standard library often lets me avoid explicit memory allocation. Would love to hear more about the motivation for this (and other aspects of your C++ usage).

Also, if you have a demo of the engine in use that would be fun to see!

Re:Show HN: Crown – A flexible game engine written from scra... by badsectoracula on Thursday June 22, 2017 @06:04AM (#14611143)
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 avoid fragmenting the heap).

Related, Andrei Alexandrescu had a great talk about allocators in C++ a couple of years ago: https://www.youtube.com/watch?v=LIb3L4vKZ7U

Also related to the Orthodox C++, the same engine also ousted exceptions and RTTI. I'm not sure about the reason for exceptions, but C++'s RTTI was simply inadequate and instead it was replaced with a custom one made using macros (similarly to wxWidgets and MFC) that allowed automatic object serialization and reflection which was used for all saving and loading, exposing objects to the editor automatically with a common UI and exposing classes and objects to the (custom) scripting language with very little setup.

Interestingly most of the stuff the engine had to reinvent seem to be first class citizens in the D language. Also Andrei's allocators also seem to be available (experimentally) there too.

Personally i prefer plain old C (C89 even, although with a few commonly available or easily reproducible extras like stdint) because i see C++ as too complex for what it is worth. However D seems to provide more power with less complexity and more and more makes me want to try it, especially the new "better C" mode that DMD has got (which i think is somewhat the D equivalent to Orthodox C++ that is linked from the page).

Re:Show HN: Crown – A flexible game engine written from scra... by agentultra on Thursday June 22, 2017 @10:06AM (#14612289)
I felt the same way dipping my toes in C++ for a few years. C99 is definitely my preferred language. But when in Rome...
Re:Show HN: Crown – A flexible game engine written from scra... by comstock on Thursday June 22, 2017 @10:08AM (#14612313)
I'm kind of curious about doing this more often, but it's the lack of clean collections that puts me off.

What do you do regarding collections? (Dynamic arrays, hashmaps)?

Re:Show HN: Crown – A flexible game engine written from scra... by agentultra on Thursday June 22, 2017 @11:15AM (#14612805)
> What do you do regarding collections? (Dynamic arrays, hash maps)?

I don't do anything!

I use the most appropriate data-structure and minimal transformation necessary to get the work done. I use maths and higher-level tools to verify my designs but the implementation, when required to be soft-realtime needs to exploit as much mechanical sympathy from my target platform as possible.

You might be interested in https://dataorientedprogramming.wordpress.com

Cheers!

Re:Show HN: Crown – A flexible game engine written from scra... by badsectoracula on Thursday June 22, 2017 @03:26PM (#14614649)
Indeed collections are a stinky bit, but fortunately they are not the majority of the code. Generally i either do a "list of pointers" (for example http://runtimeterror.com/rep/engine/artifact/0a8bb29493c782f... from my own C engine) or i define `DECLARE_LIST(type)` and `IMPLEMENT_LIST(type)` macros which declares types and functions for handling those (note that with the word list "list" in both cases i mean a conceptual list of items, not the data structure, in practice it isn't a linked list but a vector). The latter can be faster, more flexible (e.g. you can specify how the comparisons are done so that you can use == for simple stuff, strcmp for strings, memcmp for structs or custom calls for more complex structures) and more type safe but on the other hand it can be very annoying to write, debug and extend which is why i rarely do it. Another way is to use an include trick where you do something like

    #define TYPE int
    #include "list_template.h"
    #undef TYPE
with `list_template.h` using TYPE wherever a data type would be needed and defining inline (C99) and/or static (C89) functions so that they can be redefined in multiple files (or have a dedicated C file that includes the above header with all data types and an additional macro that enables the implementation). This is basically sort of implementing templates in C.

The void pointer approach is the simplest and most macro free (despite me using macros here, i'm a bit macro happy sometimes :-P) but at the same time you are limited to pointers. In practice i've found that most of the time this is enough, which is why i still haven't replaced that yet. But there are cases where i'd prefer to be able to have a list of structs instead of pointers to structs, both because it is simpler (no need to define a custom free function) and faster (less indirections), so i'll most likely replace that code with another approach (most likely the macro that defines the types, not the include header).

But if there is a single feature i'd like to see from C++ to C that would be templates, even if they are single depth. I don't even care about classes or the other stuff (classes are nice to have, but not necessary as long as the compiler can figure out that the template parameters to structs and functions with the same name refer to the same type when used together).

Re:Show HN: Crown – A flexible game engine written from scra... by netheril96 on Thursday June 22, 2017 @08:09AM (#14611644)
> dynamic strings would be isolated to their own pool to avoid fragmenting the heap

Strings have arbitrary sizes. How does pooling them together reduce fragmentation? Do they always come and go in groups?

Re:Show HN: Crown – A flexible game engine written from scra... by moomin on Thursday June 22, 2017 @08:16AM (#14611667)
I think it reduces fragmentation in the other pools, not the string pool.
Re:Show HN: Crown – A flexible game engine written from scra... by syrail on Thursday June 22, 2017 @03:03PM (#14614467)
Bingo. This helps restrict the fragmentation from dynamic strings to one pool of memory, allowing the others to remain nicely packed, aligned, etc (whatever your ideal for them is).
Re:Show HN: Crown – A flexible game engine written from scra... by ryandrake on Thursday June 22, 2017 @10:13AM (#14612343)
> 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 stuff.

Re:Show HN: Crown – A flexible game engine written from scra... by yoklov on Thursday June 22, 2017 @10:54AM (#14612638)
IME most of it is due to how bad c++'s builtin allocator support is though. C++11 helps a little but a lot of stuff you might want to do seemed to be impossible last time I looked. This is awful since games will often use pools and arenas, often heavily.

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 scra... by stevenwoo on Thursday June 22, 2017 @10:43AM (#14612566)
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 scra... by ryandrake on Thursday June 22, 2017 @10:55AM (#14612654)
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.
Re:Show HN: Crown – A flexible game engine written from scra... by pixel_fcker on Friday June 23, 2017 @02:53AM (#14617433)
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 have said though, the main reason it's used (and the reason I was interested even though I don't do games) is because the allocation story in the stdlib sucks.

Re:Show HN: Crown – A flexible game engine written from scra... by stevenwoo on Sunday June 25, 2017 @10:08PM (#14633536)
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 scra... by to3m on Thursday June 22, 2017 @03:14PM (#14614556)
You might also do this to improve debuggability and unoptimised build performance. The VC++ stdlib is particularly bad, as its authors have gone down the ultra-DRY rabbit hole even for simple stuff - a pain to step through, and it relies entirely on the optimizer doing its thing.

(libstdc++'s vector looks sensible in this respect - a good decision on their part. Haven't looked at any other aspects of it though.)

At one point the contents of vectors were often inconvenient to examine in just about every debugger, because you'd have to type out some infeasibly long expression to get at them, "vec._Mybase._Myval._Myptr[0]", that kind of thing, which you could also fix by writing your own container and simply calling your pointer field something like "p". (Same goes for smart pointers.) Luckily this is much improved in the latest Visual Studio but it may still be an issue elsewhere.

Re:Show HN: Crown – A flexible game engine written from scra... by badsectoracula on Thursday June 22, 2017 @03:50PM (#14614803)
> I wonder if any of these shops regularly measure the performance of their custom containers

Yes, while it wasn't often, we sometimes did benchmark tests to improve performance when bottlenecks were found, especially towards the game's release when we were focusing on optimizations. IIRC we did some minor changes in the dynamic array container and we rewrote the hashmap and hashset implementations. One of the programmers wrote a performance test comparing several algorithms both with synthetic and real data (from the case that created the bottleneck).

> 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 stuff.

There are other reasons to use a custom container than just the pure performance of the container itself. One is using a different allocation scheme, as the example i gave in the grandparent post, another is to use a friendlier API (see `find` and friends) and add more features. An important one in our engine was support for the custom RTTI that was used for object serialization and the scripting language that also worked and exposed those directly - the container, the RTTI implementation and the scripting runtime had to have intimate knowledge about each other to work transparently (especially when the editor entered the picture, where you could create new entries, often objects but also sometimes structs or other data types, by editing the array directly in a property editor).

Of course not all engines do that and TBH most of the performance and memory related bits are more relevant to consoles than (desktop) PCs (the API friendliness and RTTI stuff are platform agnostic though :-P). At the previous gaming company i worked at, the engine used standard containers. Also AFAIK the engine used by the Two Worlds games also uses standard containers (based on some of their developers' comments).

Personally when i write C++ i implement my own containers not because of performance but simply because i dislike the STL API - for example i want to have "Find", "IndeOf", "Swap", etc methods in the container itself :-P. Sadly it seems that i'll also need to do the same if i decide to start working with D seriously since D's standard library seem to more or less copy the STL API style.

Re:Show HN: Crown – A flexible game engine written from scra... by lj3 on Thursday June 22, 2017 @12:53PM (#14613561)
> I wonder if any of these shops regularly measure the performance of their custom containers

You don't know? Maybe you should find out before slinging around accusations of cargo cultism.

Re:Show HN: Crown – A flexible game engine written from scra... by ryandrake on Thursday June 22, 2017 @01:03PM (#14613638)
Of course I don't know--that's why I said "I wonder". I have, however, worked in non-game-developing companies who eschewed the standard library, and when pressed the argument boiled down to: someone who worked here long ago said the STL was slow and therefore we don't use it. I am _wondering_ if it's the same story at other companies.
Re:Show HN: Crown – A flexible game engine written from scra... by dbartolini on Thursday June 22, 2017 @06:00AM (#14611133)
I do not use STL because I want consistent implementation across all supported platforms. Also, you have to care about memory management when you need performance or when working with memory constrained devices. The way STL deals with custom allocators makes no sense to me, hence my own implementation.

You can find demos in the `samples` folder. :)

Re:Show HN: Crown – A flexible game engine written from scra... by moomin on Thursday June 22, 2017 @08:17AM (#14611678)
Show me a man who thinks STL allocators make complete sense, and I'll show you a man with some serious cognitive issues.
Re:Show HN: Crown – A flexible game engine written from scra... by dagw on Thursday June 22, 2017 @06:11AM (#14611165)
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

Re:Show HN: Crown – A flexible game engine written from scra... by torrent-of-ions on Thursday June 22, 2017 @07:27AM (#14611426)
What is "a standard implementation"?
Re:Show HN: Crown – A flexible game engine written from scra... by IshKebab on Thursday June 22, 2017 @07:38AM (#14611480)
By far the most used implementations are GNU's libstdc++ LLVM's libc++ and Microsoft's CRT.
Re:Show HN: Crown – A flexible game engine written from scra... by dagw on Thursday June 22, 2017 @07:47AM (#14611524)
The one that you get by default with your operating systems most popular C++ tool chain.
Re:Show HN: Crown – A flexible game engine written from scra... by thehardsphere on Thursday June 22, 2017 @05:57AM (#14611122)
Yeah, I'd like to know why you'd still use C++ at all if you find Orthodox C++ appealing. It would seem easier to just write C. Unless I'm missing something (I probably am; don't write enough of either one to have an informed opinion, which is why I'd love to hear more about this).
Re:Show HN: Crown – A flexible game engine written from scra... by dgfgfdagasdfgfa on Thursday June 22, 2017 @06:18AM (#14611185)
RAII is incredibly attractive, especially if you disable exceptions.
Re:Show HN: Crown – A flexible game engine written from scra... by tjoff on Thursday June 22, 2017 @07:24AM (#14611409)
Why would RAII be especially attractive if disabling exceptions?
Re:Show HN: Crown – A flexible game engine written from scra... by mbel on Thursday June 22, 2017 @07:43AM (#14611509)
Probably because exceptions are the biggest source of pain with RAII.
Re:Show HN: Crown – A flexible game engine written from scra... by tjoff on Thursday June 22, 2017 @07:46AM (#14611521)
I'd say that exceptions are the biggest source of pain if you don't have RAII.

Or, rephrased: RAII is incredibly attractive, especially when exceptions are being used.

Re:Show HN: Crown – A flexible game engine written from scra... by dgfgfdagasdfgfa on Thursday June 22, 2017 @03:57PM (#14614855)
RAII is necessary for exceptions. Why the hell would you do that to yourself?
Re:Show HN: Crown – A flexible game engine written from scra... by leni536 on Thursday June 22, 2017 @08:10AM (#14611646)
How do you deal with constructors that might fail?
Re:Show HN: Crown – A flexible game engine written from scra... by adrift on Thursday June 22, 2017 @08:47AM (#14611844)
You don't have constructors that 'fail'.
Re:Show HN: Crown – A flexible game engine written from scra... by ryandrake on Thursday June 22, 2017 @10:14AM (#14612354)
So, allocating memory for objects is not part of construction? Again, why not just stick with C?
Re:Show HN: Crown – A flexible game engine written from scra... by eropple on Thursday June 22, 2017 @11:23AM (#14612857)
Memory for objects is allocated structurally as part of the object, not dynamically, wherever possible. And it's usually very possible. If you can't do that, provide an initialization method. (In almost all cases, I would personally prefer hiding that two-phase initialization within a factory function.)

As for "why not stick with C"--all of the other reasons still hold true, from templates on down. The simple existence of dtors with viable scope guards that are guaranteed to fire when exiting scope is reason enough for me to never write C and to look with a default skepticism on any codebase that thinks its developers are perfect enough not to need them.

Re:Show HN: Crown – A flexible game engine written from scra... by mbel on Thursday June 22, 2017 @11:23AM (#14612855)
> Again, why not just stick with C?

The thing that is hard to replicate in C is destructors. Automatic deinitialization when leaving scope in very convenient. It allows you to have multiple exists from the scope without preceding each of them with prologue of dinit_*() calls or creating single exit point and jumping to it.

Coupling allocation with initialization is trivial to do without C++ constructors (which I find to be very poorly designed).

Re:Show HN: Crown – A flexible game engine written from scra... by to3m on Thursday June 22, 2017 @11:32AM (#14612935)
C doesn't let you have destructors that automatically clean up whatever got initialised in the Init method (if it was called), but C++ does.
Re:Show HN: Crown – A flexible game engine written from scra... by maccard on Thursday June 22, 2017 @06:23AM (#14611200)
If you disable exceptions hoe do you handle failures in constructors?
Re:Show HN: Crown – A flexible game engine written from scra... by dgfgfdagasdfgfa on Thursday June 22, 2017 @06:31AM (#14611229)
I mean it's kind of a smartass answer, but—don't fail during constructors. Move all possible code that can fail into an initialize method; check explicitly for allocation failure and/or put things on the stack instead of heap when possible; consider failing hard with a stack trace or core dump over catching and processing exceptions before (likely) failing anyway.
Re:Show HN: Crown – A flexible game engine written from scra... by dan00 on Thursday June 22, 2017 @07:30AM (#14611447)
Instead of using a constructor you can use a constructor method e.g.:

    class Foo {
       public:
          static std::optional<Foo> create();

       private:
          Foo();
    };
Re:Show HN: Crown – A flexible game engine written from scra... by maccard on Thursday June 22, 2017 @08:22AM (#14611697)
In general if you're not using exceptions, you're not going to be using features that haven't actually been published in a formal standard (optional).

This now means that you can't use any constructors, so how do you have Containers of foo?

Re:Show HN: Crown – A flexible game engine written from scra... by imron on Thursday June 22, 2017 @09:06AM (#14611925)
> you're not going to be using features that haven't actually been published in a formal standard (optional).

So you then have things like:

  class Foo
  {
  public:
    static Foo* create();
    ...
  };
  ...
  Foo* foo = Foo::create()
  if ( foo != nullptr ) ...
> so how do you have Containers of foo?

std::vector<Foo*>

Not saying either of those are better than the alternative (I prefer using exceptions and RAII), just pointing out what I've seen in real world projects.

Re:Show HN: Crown – A flexible game engine written from scra... by mikepurvis on Thursday June 22, 2017 @10:07AM (#14612299)
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 that you drive the risky pieces from outside the object, rather than monolithically from within.

This has a further benefit for testing, since you can use your major objects without fully initializing the entire world that they depend on.

Re:Show HN: Crown – A flexible game engine written from scra... by imron on Thursday June 22, 2017 @10:29AM (#14612459)
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.

Re:Show HN: Crown – A flexible game engine written from scra... by gpderetta on Thursday June 22, 2017 @10:59AM (#14612673)
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 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 scra... by imron on Thursday June 22, 2017 @11:16AM (#14612811)
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 and can't forget to call initialize code
  
  if ( foo ) //check for non-null, note, if using an optional you'd also need a similar check
  {
    ...
  }
Now the only way to create a Foo object is through the create() function and there is no separated initialize - it all happens in the same place.

This pattern of using a static create method is explicitly designed to avoid 2PI and is very common, especially in codebases that disable exceptions.

Also note that I'm not personally advocating using it, just that it is commonly used to avoid 2PI.

Re:Show HN: Crown – A flexible game engine written from scra... by maccard on Friday June 23, 2017 @09:22AM (#14618942)
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<Foo>)
Re:Show HN: Crown – A flexible game engine written from scra... by imron on Friday June 23, 2017 @11:10AM (#14619707)
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 scra... by mikepurvis on Friday June 23, 2017 @01:11PM (#14620813)
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 scra... by imron on Thursday June 22, 2017 @11:37AM (#14612968)
> 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.

Re:Show HN: Crown – A flexible game engine written from scra... by gpderetta on Thursday June 22, 2017 @12:02PM (#14613172)
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.
Re:Show HN: Crown – A flexible game engine written from scra... by imron on Friday June 23, 2017 @02:57AM (#14617443)
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 scra... by dan00 on Thursday June 22, 2017 @10:30AM (#14612466)
My bad, I thought std::optional is part of C++14, it seems to be part of the next standard C++17, but there's still boost::optional.

About the container issue: if you have objects that might fail during the creation it seems like a bad idea to allow things like:

    std::vector<Foo> foos(10);
Having a separate initialization method which might fail - like proposed by others - is another option, but this means your objects need some kind of internal initialization state, and whenever you're handling such an object you never can be absolute sure that it's in a valid state.

I'm quite a big fan of making invalid state not representable in an object and handling failure cases as early as possible.

What the create method returns depends heavily on your use case. If the returned objects can always be allocated on the heap, then a pointer or unique_ptr can be returned.

Re:Show HN: Crown – A flexible game engine written from scra... by ryandrake on Thursday June 22, 2017 @11:08AM (#14612748)
How would you handle failure in copy constructors?
Re:Show HN: Crown – A flexible game engine written from scra... by dan00 on Thursday June 22, 2017 @11:19AM (#14612827)
Most likely having an explicit copy method instead of a copy constructor.
Re:Show HN: Crown – A flexible game engine written from scra... by badsectoracula on Thursday June 22, 2017 @06:06AM (#14611147)
Well, you still get classes and templates.
Re:Show HN: Crown – A flexible game engine written from scra... by dbartolini on Thursday June 22, 2017 @08:26AM (#14611713)
Sensible usage of templates, operator overloading and namespaces is ok.