c++ - push_back - vector:: emplace_back para objetos con un constructor privado
c++ emplace back (2)
Quiero que mis objetos Timer se creen solo a través de Timer :: create (). Para ello, hice el constructor privado. Sin embargo, recibo un error del compilador que dice que "Timer :: Timer (unsigned int) ''es privado" dentro del contexto de new_allocator.h. ¿Como puedó resolver esté problema?
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;
Probablemente deberías implementar tu propio asignador, que será amigo a temporizador:
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);
}
La solución más sencilla sería derivar de std::allocator<Timer>
y volver a implementar el enlace para que se vuelva a enlazar a sí mismo, por lo que el vector
no podría volver a enlazar el asignador con std::allocator
e implementar la propia construct
para crear realmente los Timer
.
Puede utilizar la semántica de transferencia de amistad para evitar tener que tener un asignador de vector
especializado. Es un poco como dependencia de la inyección de amistad. Esto es realmente muy simple. Creas una clase vacía que se hace un amigo de tu clase. Pero el constructor predeterminado es privado, por lo que solo su clase puede crear instancias de él. Pero la clase sigue siendo copiable, por lo que se puede pasar a cualquiera.
Su constructor Timer
será público, pero requiere uno de estos objetos como argumento. Por lo tanto, solo su clase, o una función llamada por ella, puede crear estos objetos directamente (las copias / movimientos aún funcionarán).
Así es como puedes hacer eso en tu código ( ejemplo en vivo ):
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;