Vector::emplace_back用于具有私有构造函数的对象

vector::emplace_back for objects with a private constructor

本文关键字:构造函数 对象 用于 emplace back Vector      更新时间:2023-10-16

我想通过Timer::create()只创建我的定时器对象。为此,我将构造函数设为私有。然而,在new_allocator.h的上下文中,我得到一个编译器错误,说"Timer::Timer(unsigned int)'是私有的"。我该如何解决这个问题?

class Timer {
    private:
        int timeLeft;
        Timer(unsigned int ms) : timeLeft(ms) {}
    public:
        static std::vector<Timer> instances;
        static void create(unsigned int ms) {
            instances.emplace_back(ms);
        }
};
std::vector<Timer> Timer::instances;

您可以使用友谊传递语义来避免使用专门的vector分配器。这有点像友谊的依赖注入。这真的很简单。您创建了一个空类,它将自己作为您的类的朋友。但是默认构造函数是私有的,所以只有你的类可以创建它的实例。但是这个类仍然是可复制的,所以它可以传递给任何人。

您的Timer构造函数将是公共的,但它需要这些对象中的一个作为参数。因此,只有你的类,或者它调用的函数,可以直接创建这些对象(复制/移动仍然可以工作)。

下面是你如何在你的代码中做到这一点(实际示例):
class TimerFriend
{
public:
  TimerFriend(const TimerFriend&) = default;
  TimerFriend& operator =(const TimerFriend&) = default;
private:
  TimerFriend() {}
  friend class Timer;
}
class Timer {
    private:
        int timeLeft;
    public:
        Timer(unsigned int ms, const TimerFriend&) : timeLeft(ms) {}
        static std::vector<Timer> instances;
        static void create(unsigned int ms) {
            instances.emplace_back(ms, TimerFriend());
        }
};
std::vector<Timer> Timer::instances;

您可能应该实现您自己的分配器,这将是定时器的朋友:

class Timer {
    struct TimerAllocator: std::allocator<Timer>
    {
        template< class U, class... Args >
        void construct( U* p, Args&&... args )
        {
            ::new((void *)p) U(std::forward<Args>(args)...);
        }
        template< class U > struct rebind { typedef TimerAllocator other; };
    };
    friend class TimerAllocator;
    private:
        int timeLeft;
    Timer(unsigned int ms) : timeLeft(ms) 
    {}
    public:
        static std::vector<Timer, TimerAllocator> instances;
        static void create(unsigned int ms) {
            instances.emplace_back(ms);
        }
};
std::vector<Timer, Timer::TimerAllocator> Timer::instances;
int main()
{
    Timer::create(100);
}

最简单的解决方案是由std::allocator<Timer>重新实现rebind来重新绑定自己,因此vector不能将分配器重新绑定回std::allocator并实现自己的construct来实际创建Timer s。