Vector:: emplace_back для объектов с частным конструктором
Я хочу, чтобы мои объекты Timer создавались только с помощью Timer:: create(). Для этого я сделал конструктор закрытым. Тем не менее, я получаю ошибку компилятора, говоря, что "Timer:: Timer (unsigned int)" является приватным "в контексте new_allocator.h. Как я могу решить эту проблему?
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;
Ответы
Ответ 1
Вероятно, вы должны реализовать свой собственный распределитель, который будет дружественным к таймеру:
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.
Ответ 2
Вы можете использовать семантику передачи-дружбы, чтобы избежать необходимости иметь специализированный распределитель 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;