我有一对函数init
和shutdown
以及一些类RefTest
。
我需要在首次实例化RefTest
时调用init
,并在销毁RefTest
的最后一个实例时调用shutdown
。这也可能在一个程序中多次发生。
我想出的一个实现如下所示。但这对我来说似乎并不理想(例如,它不是线程安全的(。 我想过使用std::shared_ptr
并将这些功能放在类 ctor/dtor 中,但我似乎无法让它工作。
有没有更好的方法可以做到这一点?
测试实现:
#include <iostream>
void init() { std::cout << "init() called" << std::endl; }
void shutdown() { std::cout << "shutdown() called" << std::endl; }
static size_t s_refCount = 0;
class RefTest
{
public:
explicit RefTest()
{
if(s_refCount++ == 0) init();
std::cout << "ctor()" << std::endl;
}
~RefTest()
{
std::cout << "dtor()" << std::endl;
if(--s_refCount == 0) shutdown();
}
};
int main(int argc, char *argv[])
{
{
RefTest t1;
RefTest t2;
RefTest t3;
}
RefTest t4;
return 0;
}
输出:
init() called
ctor()
ctor()
ctor()
dtor()
dtor()
dtor()
shutdown() called
init() called
ctor()
dtor()
shutdown() called
对我来说似乎并不理想(例如,它不是线程安全的(。
std::atomic<int>
帮助解决这个问题 - 但只是问题的一部分。它可以使计数器线程安全,这样您就不会尝试调用init
/shutdown
太多次。
它不会解决在第一次调用仍在执行时第二次调用构造函数的问题。(然后使用部分构造的对象(
有没有更好的方法可以做到这一点?
普遍接受的最佳做法是为每个类分配一个作业。
例:
#include <iostream>
#include <atomic>
// one class, one job
struct initialiser
{
initialiser()
{
if (0 == s_refCount++) init();
}
initialiser(initialiser const&)
{
++s_refCount;
}
initialiser& operator=(initialiser const&)
{
++s_refCount;
return *this;
}
~initialiser()
{
if(--s_refCount == 0) shutdown();
}
private:
void init() { std::cout << "init() called" << std::endl; }
void shutdown() { std::cout << "shutdown() called" << std::endl; }
static std::atomic<size_t> s_refCount;
};
std::atomic<size_t> initialiser::s_refCount { 0 };
// one class, one job. Allow encapsulation to do the reference counting
class RefTest
{
public:
explicit RefTest()
{
std::cout << "ctor()" << std::endl;
}
// rule of 5
RefTest(RefTest const &) = default;
RefTest(RefTest &&) = default;
RefTest& operator=(RefTest const &) = default;
RefTest& operator=(RefTest &&) = default;
~RefTest()
{
std::cout << "dtor()" << std::endl;
}
private:
initialiser init_;
};
int main(int argc, char *argv[])
{
{
RefTest t1;
RefTest t2;
RefTest t3;
}
RefTest t4;
return 0;
}
预期产出:
init() called
ctor()
ctor()
ctor()
dtor()
dtor()
dtor()
shutdown() called
init() called
ctor()
dtor()
shutdown() called
另请注意不违反 3/5 规则