It isn't. You probably should throw an exception if cin fails, since otherwise data is just uninitialized. (And it also writes to a local data.)
However, you could do input in a function that returns the entered value (and throws if input fails.) Probably in all cases you can either get the data to be used for initialization from a function. Or compute it first and provide a suitable constructor.
But here's your original class in somewhat better style as I believe.
Main changes: assignment operator shouldn't freak out if one or both are empty holders, since it is a valid state for this class. destroy is a private method, since the user doesn't really need it (the example shows how you can reset a holder earlier if you are desperate). asserts should be done in the place where it would be an error to continue (that's the casts in getObj) - for this reason code had to be reordered in the destroy method.
#include <cassert>// Note: Currently supports objects with zero, one or two parameter c'torstemplate <class T>class Holder {public: Holder():created(false) { } ~Holder() { destroy(); } Holder(const Holder<T> &other): created(false) { if (other.created) { create(other.getObj()); } } Holder<T> & operator=(const Holder<T> &other) { if (this == &other) { return *this; } if (!other.created) { destroy(); } else if (!created) { create(other.getObj()); } else { getObj() = other.getObj(); } return *this; } T* operator->() { return &getObj(); } const T* operator->() const { return &getObj(); } T & operator*() { return getObj(); } const T & operator*() const { return getObj(); } void create() { new (obj) T; created = true; } template <class P1> void create(const P1 &p1) { new (obj) T(p1); created = true; } template <class P1, class P2> void create(const P1 &p1, const P2 &p2) { new (obj) T(p1, p2); created = true; }private: T& getObj() { assert(created && "Holder holds no instance"); return *(reinterpret_cast<T*>(obj)); } const T& getObj() const { assert(created && "Holder holds no instance"); return (const_cast<Holder<T>*>(this))->getObj(); } void destroy() { if (created) { getObj().~T(); created = false; } } char obj[sizeof(T)]; bool created;};#include <iostream>#include <string>using namespace std;struct Student { string name; int grade; Student(const string &name, int grade) : name(name), grade(grade) { cout << "Student::Student() for " << name << endl; } ~Student() { cout << "Student::~Student() for " << name << endl; } void print() const { cout << name << ", " << grade << endl; }};int main(){ Holder<Student> st1; Holder<Student> st2; cout << "Hello" << endl; st1.create("John", 87); st2.create("Mike", 92); st1->print(); (*st2).print(); st2 = st1; st2->print(); st1 = Holder<Student>(); cout << "Goodbye" << endl;}