Use shared_ptr in Game Engine layout? - c++

I have written a little game engine in c++ and it works ok but is not the best performance wise. I also learned a lot and I want to redo it now. But last time I heavily used shared_ptr for classes like gui textures and model wrappers (that hold i.e. the 3d position and the opengl vao). I've heared that shared_ptr should not really be used, but I dont really know how to do it any other way. Here's the pseudo-code-like layout:
This code is not complete or working but I want to share the idea of my layout
// d3 stands for 3d
class D3Model {
VAO vao;
bool useBloom;
unsigned int texture;
// ... and so on
static std::vector<std::shared_ptr<D3Model>> models; // current idea, approach 1
static std::vector<D3Model> models1; // different approach (2)
D3Model() {
models.push_back(shared_from_this()); // app.1
models1.push_back(*this);
}
}
// main file
int main() {
std::shared_ptr<D3Model> model = std::make_shared<D3Model>();
model->setTexture(0); // ignore the non sense content
D3Model model1;
model1.setTexture(0); // would not get updated in the vector
while(true) {
model->increaseRotation(1);
model1.increaseRotation(1);
Renderer::render();
}
}
// different file
class Renderer {
static void render() {
for(const auto& all : D3Model::models) {
// render model
}
for(const auto& all : D3Model::models1) {
// render model1, would not have increased rotation
}
}
}
For more clarification, imagine the following use of the engine:
After hitting play on a start screen, the engine loads some 3d models from files and stores them. One of them gets rotated every frame and every one of them gets rendered. Maybe some other models must be loaded after because of a change in gameplay (Player joined...). Then they all get deleted when the user returns to the main menu. My problem with approach 2 is that I'd have to update the vector everytime the rotation of the model is increased, whereas that would automatically be handled with approach 1. However, I have heared that shared_ptr is bad for performance.
Is shared_ptr for this case the best solution or should I just use normal objects? But my problem with that is how would I apply changes to the object (the setTexture for example) without having to update the vector content. And raw pointers arent really good either. How is something like that done?
Thanks, unreal

Ok you can create yor own RefCouner class like me:
/// RefCounter.hpp
#pragma once
class RefCounter {
public:
RefCounter();
RefCounter(const RefCounter&);
RefCounter& operator=(const RefCounter&);
void grab();
usize reference() const;
bool release();
protected:
virtual void finalize();
virtual ~RefCounter();
private:
usize _reference;
};
template<typename T>
struct ref {
inline ref() : class_ptr (nullptr) {}
inline ref(T* obj) : class_ptr (obj) { if(class_ptr) class_ptr->grab(); }
inline ref(const ref& other) : class_ptr (other.class_ptr) { if(class_ptr) class_ptr->grab(); }
inline ref& operator=(T* obj) {
if(obj)
obj->grab();
if(class_ptr)
class_ptr->release();
class_ptr = obj;
return *this;
}
inline ref& operator=(const ref& other){
T* obj = other.class_ptr;
if(obj)
obj->grab();
if(class_ptr)
class_ptr->release();
class_ptr = obj;
return *this;
}
T* get() const {
return class_ptr;
}
operator T*() const {
return class_ptr;
}
T* operator->() const {
return class_ptr;
}
inline ~ref() {
if(class_ptr)
class_ptr->release();
}
private:
T* class_ptr;
};
/// RefCounter.cpp
RefCounter::RefCounter() : _reference(0){
}
RefCounter::RefCounter(const RefCounter&) : _reference(0) {
}
RefCounter& RefCounter::operator=(const RefCounter&) {
return *this;
}
void RefCounter::grab() {
_reference++;
}
usize RefCounter::reference() const {
return _reference;
}
bool RefCounter::release() {
if(_reference > 1) {
_reference--;
return false;
} else {
_reference = 0;
finalize();
return true;
}
}
void RefCounter::finalize() {
delete this;
}
RefCounter::~RefCounter() {
}

Related

Compare the habits between move and smart pointer in C++?

In C++11/14, an object can be transfered by move or smark pointer.
(1) This is an example for move:
class MoveClass {
private:
int *tab_;
int alloc_;
void Reset() {
tab_ = nullptr;
alloc_ = 0;
}
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
MoveClass() : tab_(nullptr), alloc_(0) {}
~MoveClass() {
Release();
}
MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
other.Reset();
}
MoveClass & operator=(MoveClass && other) {
if (this == &other) return *this;
std::swap(tab_, other.tab_);
std::swap(alloc_, other.alloc_);
return *this;
}
void DoSomething() { /*...*/ }
};
When we use this movable MoveClass, we can write code like this :
int main() {
MoveClass a;
a.DoSomething(); // now a has some memory resource
MoveClass b = std::move(a); // move a to b
return 0;
}
Always write move-constructor/move-operator= is boring, use shared_ptr/unique_ptr some times have the same effect, just like java, reference/pointer everywhere.
(2) Here is the example:
class NoMoveClass {
private:
int *tab_;
int alloc_;
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
NoMoveClass() : tab_(nullptr), alloc_(0) {}
~NoMoveClass() {
Release();
}
MoveClass(MoveClass && other) = delete;
MoveClass & operator=(MoveClass && other) = delete;
void DoSomething() { /*...*/ }
};
We can use it like this:
int main() {
std::shared_ptr<NoMoveClass> a(new NoMoveClass());
a->DoSomething();
std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
return 0;
}
Is it a good habit to always use the 2nd one?
Why many libraries, STL use the 1st one, not the 1st one ?
Always write move-constructor/move-operator= is boring
You almost never need to write your own move constructor/assignment, because (as you mentioned) C++ supplies you with a number of basic resource managers - smart pointers, containers, smart locks etc.
By relying on those in your class you enable default move operations and that results in minimal code size as well as proper semantics:
class MoveClass {
private:
std::vector<int> data;
public:
void DoSomething() { /*...*/ }
};
Now you can use your class as in (1) or as a member in other classes, you can be sure that it has move semantics and you did it in the minimal possible amount of code.
The point is one usually only needs to implement move operations for the most low-level classes which are probably covered already by STL, or if some weird specific behavior is needed - both cases should be really rare and not result in "Always writing move-constructor/move-operator=".
Also notice that while approach (1) is unnecessarily verbose, (2) is just unacceptable - you have a resource managing class that doesn't do its job and as a result you have to wrap it in smart pointers everywhere in your code, making it harder to understand and eventually resulting in even more code than (1)

C++ OOP: Class knows its index in the container - prevent overwrite?

I have a class idx_aware that goes into a container container, which wraps around a std::vector. When the class is added to container, container sets a pointer to itself in idx_aware, as well as the index of idx_aware in its internal memory storage.
The index is not going to change until the container is destroyed or idx_aware is removed; idx_aware needs to know about its container and its index, because it has some methods that require both to work.
Now this introduces the following problem: when I get a non-const reference to an idx_aware class contained in container, I could assign to it another idx_aware class, which could have a different index. The intention would be assigning all the fields and keeping the index as it is.
#include <vector>
#include <limits>
#include <iostream>
class container;
// Stores a std::size_t field, which can be set only by subclasses.
class with_idx {
std::size_t _i;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()) {}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) { _i = i; }
};
// Knows its index and its container
class idx_aware : public with_idx {
container const *_container;
int _some_field1;
float _some_field2;
public:
void foo() {
// Do stuff using _container and _i
}
private:
friend class container;
};
// Wraps around a std::vector
class container {
std::vector<idx_aware> _data;
public:
idx_aware &operator[](std::size_t idx) {
// Need non-const access to call foo
return _data[idx];
}
idx_aware const &operator[](std::size_t idx) const {
return _data[idx];
}
std::size_t add(idx_aware const &item) {
// Here it could potentially reuse a freed position
std::size_t free_slot = _data.size();
// Ensure _data is big enough to contain free_slot
if (_data.size() <= free_slot) {
_data.resize(free_slot + 1);
}
// Assign
_data[free_slot] = item;
_data[free_slot].set_idx(free_slot);
_data[free_slot]._container = this;
return free_slot;
}
};
int main() {
container c;
idx_aware an_item;
std::size_t i = c.add(an_item);
std::cout << c[i] << std::endl; // Prints 0
idx_aware another_item; // Created from somewhere else
// I want to set all the data in idx_aware, but the
// index should stay the same!
c[i] = another_item;
std::cout << c[i] << std::endl; // Prints numeric_limits<size_t>::max()
// Now container[i] is broken because it doesn't know anymore its index.
return 0;
}
One possible workaround would be to change with_idx in such a way that when set_idx is called, a flag is set that prevents assignment and copy operator to overwrite the _i property, like this:
class with_idx {
std::size_t _i;
bool _readonly;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()), _readonly(false) {}
with_idx(with_idx const &other) : _i(other._i), _readonly(false) {}
with_idx &operator=(with_idx const &other) {
if (!_readonly) {
_i = other._i;
}
return *this;
}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) {
_i = i;
if (i != std::numeric_limits<std::size_t>::max()) {
// This has been set by someone with the right to do so,
// prevent overwriting
_readonly = true;
} else {
// Removed from the container, allow overwriting
_readonly = false;
}
}
};
This would have the consequence of returning, after assignment, a reference to an idx_aware class with unchanged index.
idx_aware &not_in_container1 = /* ... */;
idx_aware &not_in_container2 = /* ... */;
idx_aware &in_container = /* ... */;
not_in_container1 = in_container = not_in_container2;
// std::size_t(not_in_container_1) != std::size_t(not_in_container_2)
Is there a design pattern that can model this situation in a better way? My searches were not successful.
Are there other unwanted consequences of overriding the assignment operator in this way? The limitation I pointed out in the previous example does not look too "bad".
Is there an easier solution? I thought about writing some proxy object to replace the idx_aware & return type of operator[].
Experience tells that when C++ does not do what you intend, you are likely to be misusing OOP...
Robert's comment suggested me this solution.
Why would the contained object know about its container? To be able to perform actions such as foo and provide shorthand methods that otherwise would require to have access to the container.
Let's take this functionality away from the contained object; the contained object is just data payload. Instead, let's make operator[] return not the contained object, but some sort of iterator, a wrapper around the contained object, which knows the container and the index, and once dereferenced returns the actual contained object.
class was_idx_aware {
int _some_field1;
float _some_field2;
};
class container {
std::vector<idx_aware> _data;
public:
class idx_aware_wrapper {
container const *_container;
std::size_t _idx;
public:
idx_aware_wrapper(container const &c, std::size_t i)
: _container(&c)
, _idx(i)
{}
was_idx_aware const &operator*() const {
return _container->_data[_idx];
}
was_idx_aware &operator*() {
return _container->_data[_idx];
}
void foo() {
// Do stuff using _container and _idx.
}
};
idx_aware_wrapper operator[](std::size_t i) {
return idx_aware_wrapper(*this, i);
}
/* .... */
};
This allows quick access to any data in was_idx_aware, and the wrapper class can be augmented with all the methods that require interaction with the container. No need to store and keep indices up to date or override assignment operators.

copy local objects by reference

Here's my problem,
Class MClass {
public:
void Add(OtherClass* objects) {
_objects = objects;
}
private:
OtherClass* _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
OtherClass obj[NUMBER_OF_OBJECTS];
//obj initialization here
//...
myObj.Add(obj);
}
It will cause a RT error because the *obj diminishes after the end of the function body.
But, how can make this one valid?
I like to initialized first an object before assigning it to other class.
EDIT
I don't want to use storage classes or something here, I just want a raw array since it is very expensive for me to use. Its functionality will not lessen my problem here.
So how do I do that in a raw-array style?
Class MClass {
public:
void Add(std::vector<OtherClass> objects) {
_objects = std::move(objects);
}
private:
std::vector<OtherClass> _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
myObj.Add(std::move(obj));
}
In your example, you store a pointer to a local array. If the method ends, the array goes out of scope and doesn't exist anymore.
This is the reason, your pointer is not valid anymore. If you want to solve this, learn about the scope of variables in C++.
It is not completely clear what you are trying to do, but you could store a collection of objects instead of a pointer:
class MClass
{
public:
void Add(const std::vector<OtherClass>& objects) {
objects_ = objects;
}
void Add(std::vector<OtherClass>&& objects) {
objects_ = std::move(objects);
}
private:
std::vector<OtherClass> objects_;
};
then
void Setup()
{
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
//obj initialization here
//...
myObj.Add(std::move(obj)); // move obj's contents onto myObs's objects.
}
Stop using raw arrays, and use either std::vector or std::array. Then you don't have to worry about it anymore.
If you really want to do it manually, you have to copy is manually as well. Using e.g. std::vector and std::move is more effective, but here you go:
Class MClass {
public:
MClass()
: _objects(nullptr), _count(0)
{}
MClass(const MClass& other)
: _objects(nullptr), _count(0)
{
Add(other._objects, other._count);
}
~MClass()
{
if (_objects != nullptr)
delete [] _objects;
}
void Add(const OtherClass* objects, const size_t count)
{
if (_objects != nullptr)
delete [] _objects;
_objects = new [count];
for (size_t i = 0; i < count; i++)
_objects[i] = objects[i];
_count = count;
}
MClass& operator=(const MClass& other)
{
Add(other._objects, other._count);
}
private:
OtherClass* _objects;
size_t _count;
};
// ...
myObj.Add(obj, NUMBER_OF_OBJECTS);
As you can see, it's a lot of more code, which makes it harder to follow and debug, and also larger possibility of errors. And not as "effective" as I said above.

How can I create a switch for class members?

Say I have a class with a couple of data members, and I want a class method that returns one, and the next time it is called returns the value of the other. Something like:
class MyClass
{
public:
MyClass():switch(0){};
int get();
private:
int intA, intB;
int sw;
};
int MyClass::get()
{
if ( (++sw)%2 )
return intA;
else
return intB;
}
What would a more elegant way of doing it be? I don't like the if...else statement very much. It's fine for something like return, but if I'm actually using more complex operations, I end up duplicating a ton of code. Or having to create a second method within each method that is called after I resolve what element I'm pointing to.
What I'd prefer to do, ideally, is to use some form of pointer, so I can do
class MyClass
{
public:
MyClass():switch(&intA){};
int get();
void toggleSwitch();
private:
int intA, intB;
int * sw;
};
int MyClass::get()
{
return *sw;
}
void MyClass::toggleSwitch()
{
if ( sw == &intA )
sw = &intB;
else
sw = &intA;
}
Or something to that effect. I could call toggleSwitch(), and have my class operate on either one or the other value easily.
I still don't like it though. I prefer to avoid if's when possible, and I shouldn't need one in this case. This use of a naked pointer should be pretty safe, but I was thinking I could have something like std::unique_ptr holding each element and then std::swap them. But then the pointers would own the elements, and they'd be dynamic memory instead.
So is there a better way to do it?
Well, switch is a keyword, but I'll roll with it. How about an array of pointers?
int *fields[] = {&intA, &intB};
int MyClass::get()
{
return *fields[++switch % 2];
}
This would expand nicely if you could have additional variables later.
Or maybe:
int MyClass::get()
{
return *fields[switch = 1 - switch];
}
If you return a reference then you could use get() internally.
int &MyClass::get()
{
return *fields[switch = 1 - switch];
}
I would encapsulate the concept of a toggling value:
template<typename T>
class Toggleable {
T first;
T second;
T* current;
T* other;
public:
Toggleable(const T& first, const T& second)
: first(first),
second(second),
current(&first),
other(&second) {
}
bool toggle() {
std::swap(current, other);
}
const T& get() const {
return *current;
}
}
Then use as:
class MyClass
{
Toggleable<int> value;
public:
MyClass()
: value(42, 1729)
{
}
const int& get() {
value.toggle();
return value.get();
}
};

What is the right way to switch on the actual type of an object?

I'm writing an xml parser and I need to add objects to a class generically, switching on the actual type of the object. Problem is, I'd like to keep to an interface which is simply addElement(BaseClass*) then place the object correctly.
void E_TableType::addElement(Element *e)
{
QString label = e->getName();
if (label == "state") {
state = qobject_cast<E_TableEvent*>(e);
}
else if (label == "showPaytable") {
showPaytable = qobject_cast<E_VisibleType*>(e);
}
else if (label == "sessionTip") {
sessionTip = qobject_cast<E_SessionTip*>(e);
}
else if (label == "logoffmedia") {
logoffMedia = qobject_cast<E_UrlType*>(e);
}
else {
this->errorMessage(e);
}
}
This is the calling class, an object factory. myElement is an instance of E_TableType.
F_TableTypeFactory::F_TableTypeFactory()
{
this->myElement = myTable = 0;
}
void F_TableTypeFactory::start(QString qname)
{
this->myElement = myTable = new E_TableType(qname);
}
void F_TableTypeFactory::fill(const QString& string)
{
// don't fill complex types.
}
void F_TableTypeFactory::addChild(Element* child)
{
myTable->addElement(child);
}
Element* F_TableTypeFactory::finish()
{
return myElement;
}
void F_TableTypeFactory::addAttributes(const QXmlAttributes &attribs) {
QString tName = attribs.value(QString("id"));
myTable->setTableName(tName);
}
Have you considered using polymorphism here? If a common interface can be implemented by each of your concrete classes then all of this code goes away and things become simple and easy to change in the future. For example:
class Camera {
public:
virtual void Init() = 0;
virtual void TakeSnapshot() = 0;
}
class KodakCamera : Camera {
public:
void Init() { /* initialize a Kodak camera */ };
void TakeSnapshot() { std::cout << "Kodak snapshot"; }
}
class SonyCamera : Camera {
public:
void Init() { /* initialize a Sony camera */ };
void TakeSnapshot() { std::cout << "Sony snapshot"; }
}
So, let's assume we have a system which contains a hardware device, in this case, a camera. Each device requires different logic to take a picture, but the code has to support a system with any supported camera, so we don't want switch statements littered throughout our code. So, we have created an abstract class Camera.
Each concrete class (i.e., SonyCamera, KodakCamera) implementation will incluse different headers, link to different libraries, etc., but they all share a common interface; we just have to decide which one to create up front. So...
std::unique_ptr<Camera> InitCamera(CameraType type) {
std::unique_ptr<Camera> ret;
Camera *cam;
switch(type) {
case Kodak:
cam = new KodakCamera();
break;
case Sony:
cam = new SonyCamera();
break;
default:
// throw an error, whatever
return;
}
ret.reset(cam);
ret->Init();
return ret;
}
int main(...) {
// get system camera type
std::unique_ptr<Camera> cam = InitCamera(cameraType);
// now we can call cam->TakeSnapshot
// and know that the correct version will be called.
}
So now we have a concrete instance that implements Camera. We can call TakeSnapshot without checking for the correct type anywhere in code because it doesn't matter; we know the correct version for the correct hardware will be called. Hope this helped.
Per your comment below:
I've been trying to use polymorphism, but I think the elements differ too much. For example, E_SessionTip has an amount and status element where E_Url just has a url. I could unify this under a property system but then I lose all the nice typing entirely. If you know of a way this can work though, I'm open to suggestions.
I would propose passing the responsibility for writing the XML data to your types which share a common interface. For example, instead of something like this:
void WriteXml(Entity *entity) {
switch(/* type of entity */) {
// get data from entity depending
// on its type and format
}
// write data to XML
}
Do something like this:
class SomeEntity : EntityBase {
public:
void WriteToXml(XmlStream &stream) {
// write xml to the data stream.
// the entity knows how to do this,
// you don't have to worry about what data
// there is to be written from the outside
}
private:
// your internal data
}
void WriteXml(Entity *entity) {
XmlStream str = GetStream();
entity->WriteToXml(stream);
}
Does that work for you? I've done exactly this before and it worked for me. Let me know.
Double-dispatch may be of interest. The table (in your case) would call a virtual method of the base element, which in turns calls back into the table. This second call is made with the dynamic type of the object, so the appropriate overloaded method is found in the Table class.
#include <iostream>
class Table; //forward declare
class BaseElement
{
public:
virtual void addTo(Table* t);
};
class DerivedElement1 : public BaseElement
{
virtual void addTo(Table* t);
};
class DerivedElement2 : public BaseElement
{
virtual void addTo(Table* t);
};
class Table
{
public:
void addElement(BaseElement* e){ e->addTo(this); }
void addSpecific(DerivedElement1* e){ std::cout<<"D1"; }
void addSpecific(DerivedElement2* e){ std::cout<<"D2"; }
void addSpecific(BaseElement* e){ std::cout<<"B"; }
};
void BaseElement::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement1::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement2::addTo(Table* t){ t->addSpecific(this); }
int main()
{
Table t;
DerivedElement1 d1;
DerivedElement2 d2;
BaseElement b;
t.addElement(&d1);
t.addElement(&d2);
t.addElement(&b);
}
output: D1D2B
Have a Look at the Visitor Pattern, it might help you