#include <Urho3D/Urho3DAll.h>
#include <iostream>
using namespace std;
int main()
{
Context context;
SharedPtr<Component> a, b;
shared_ptr<Component> c, d;
const long long count = 1000000LL;
for (int k = 0; k < 10; k++)
{
HiresTimer timer;
timer.Reset();
for (long long i = 0; i < count; i++)
{
a = new Component(&context);;
b = a;
}
long long elapsed = timer.GetUSec(false);
cout << "Urho3D::SharedPtr " << elapsed << "\n";
timer.Reset();
for (long long i = 0; i < count; i++)
{
c = make_shared<Component>(&context);
d = c;
}
elapsed = timer.GetUSec(false);
cout << "std:shared_ptr " << elapsed << "\n";
}
// Prevent throw out pieces of code by compiler optimizer.
clog << "Ignore it: " << b.Null() << d.use_count();
// Prevent crash on exit when context deleted before objects.
a.Detach();
b.Detach();
}
maybe itās because Urho uses intrusive reference counting, with everything inheriting from RefCounted?
So weāre getting 2 ref counts with std::shared_ptr instead of one.
To fix the comparison youāll need to create a class that inherits from RefCounted for Urho, and the same class without inheriting from RefCounted for std::shared_ptr.
This is how I corrected the code:
#include <Urho3D/Urho3DAll.h>
#include <iostream>
using namespace std;
struct TestUrho : RefCounted
{
int x = 0;
};
struct Test
{
int x = 0;
};
int main()
{
SharedPtr<TestUrho> a, b;
shared_ptr<Test> c, d;
const long long count = 1000000LL;
for (int k = 0; k < 10; k++)
{
HiresTimer timer;
timer.Reset();
for (long long i = 0; i < count; i++)
{
a = MakeShared<TestUrho>();
b = a;
}
long long elapsed = timer.GetUSec(false);
cout << "Urho3D::SharedPtr " << elapsed << "\n";
timer.Reset();
for (long long i = 0; i < count; i++)
{
c = make_shared<Test>();
d = c;
}
elapsed = timer.GetUSec(false);
cout << "std:shared_ptr " << elapsed << "\n";
}
// Prevent throw out pieces of code by compiler optimizer.
clog << "Ignore it: " << b.Null() << d.use_count();
}
std::shared_ptr adds ref count externally, and Urho3D::SharedPtr can only be used with classes that inherit from Urho3D::RefCounted, so my benchmark is correct.
void CrowdAgent::OnCrowdUpdate(dtCrowdAgent* ag, float dt)
{
...
// Use pointer to self to check for destruction after sending events
WeakPtr<CrowdAgent> self(this);
...
crowdManager_->SendEvent(E_CROWD_AGENT_REPOSITION, map);
if (self.Expired())
return;
...
}
If I understand correctly, enable_shared_from_this stores shared_ptr inside function and to allow deleting shared_ptr outside we need crazy constructions inside function to get weak_ptr from shared_ptr and delete shared_ptr
enable_shared_from_this requires to store weak_ptr in object, so⦠we get same overhead for object size, as when inheriting from Urho3D: RefCounted
You can not recieve this weak_ptr directly. You can recieve only share_ptr, convert to weak_ptr and then delete shared_ptr to allow self-destruct object outside function and get correct num refs in weak_ptr inside function
Iāve been using STL-only in my local fork for quite a while, I havenāt had a single issue or encountered anything that could not be done that the Urho containers were doing.
The switch also made it a lot easier to work with 3rd-party libraries that are almost always going to be using STL as well as concurrency primitives that I had to have for multithreaded rendering.
Cannot spawn weak/shared ptr from ctor.
And yes, it was a problem in my day job projects.
E.g. I was working with async server, and thereās no way to spawn tasks from ctor.
it sounds a bit dangerous to use an object that wasnāt fully constructed yet, itās kinda like as if itās uninitialized.
You can always use some helper function that construct the object, then passes it to some other function.
BTW not all Urho objects need to use ref counting (ex: a subsystem with a known lifetime, usually until the program shuts down), and using std::shared_ptr gives the flexibility to choose not to.
Meh, itās sometimes dangerous. It wasnāt my case tho. Async task manager needs weak ptr just to automatically cancel tasks if owner is destroyed. And thereās no way to use it from ctor, despite itās completely safe.
As an experiment and optimization for cache locality, I moved refCounter from external structure into Object. WeakRefCounter still stay as external structure, so external counter created only when WeakPointers is used. In my tests, I did not see any difference of FPS. So I believe that pointers do not affect overall performance compared to other things ā physics, rendering, and so on.