W poniższym kodzie while (!Ref.expired());
jest z radością zoptymalizowany w nieskończoną pętlę. Jeśli linia kodu zostanie zmieniona na while (!Ref.lock());
. wszystko działa zgodnie z oczekiwaniami. Tak więc dwa pytania naprawdę:Dlaczego std :: weak_ptr :: expired zoptymalizowano?
1) W jaki sposób kompilator optymalizuje czas wygasania, gdy std::weak_ptr::expired()
uzyskuje dostęp do zabezpieczonego przed zapisem licznika?
2) Czy w rzeczywistości jest to bezpieczne, czy też można je zoptymalizować?
Przykładowy kod poniżej.
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
class A
{
public:
A()
{
m_SomePtr = std::make_shared<bool>(false);
}
virtual ~A()
{
std::weak_ptr<bool> Ref = m_SomePtr;
m_SomePtr.reset();
// Spin (will be optimised into an infinite loop in release builds)
while (!Ref.expired());
}
std::shared_ptr<bool> GetPtr() const { return m_SomePtr; }
private:
std::shared_ptr<bool> m_SomePtr;
};
class B
{
public:
B(std::shared_ptr<bool> SomePtr) : m_Ref(SomePtr) {}
void LockPtr() { m_SomePtr = m_Ref.lock(); }
void UnLockPtr() { m_SomePtr.reset(); }
private:
std::shared_ptr<bool> m_SomePtr;
std::weak_ptr<bool> m_Ref;
};
int main()
{
std::unique_ptr<A> a(new A());
std::unique_ptr<B> b(new B(a->GetPtr()));
b->LockPtr();
std::cout << "Starting " << std::endl;
std::thread first([&]()
{
std::this_thread::sleep_for(std::chrono::seconds(5));
b->UnLockPtr();
});
std::thread second([&]()
{
a.reset(nullptr);
});
first.join();
second.join();
std::cout << "Complete" << std::endl;
return 0;
}
przegłosowano na ** z radością ** * zoptymalizowano z dala *. sugerujesz, że maszyny i/lub programy mogą się dobrze bawić? – Walter
@Walter Miałem wyraźne wrażenie, że kompilator był bardzo zadowolony z siebie. Ja jednak byłam bardzo _displeased_. Kompilator i ja mamy burzliwy związek. –
[Wydaje się pracować z gcc] (http://coliru.stacked-crooked.com/a/36ffe423f76ecf02). [Działa również z klangiem] (http://coliru.stacked-crooked.com/a/5b3827c261b54b90). Prawdopodobnie błąd w studiu visual. – interjay