jeudi 4 février 2016

Rule of zero in C++11

I am a newbie in C++ and have the following doubt concerning the Rule of Zero: can we use a deep-copy smart pointer compatible with polymorphism as a member-variable of a class without the need to declare any of the special member-functions (i.e. relying only on synthesized)???

For example, the following code surprisingly appears to work:

#include <iostream>
#include <cassert>
using namespace std;

template<typename Value>
struct Inteligent
{
private:
 template <typename OtherValue>
 friend struct Inteligent;
 Value* pointer;

public:
 Inteligent():pointer{nullptr}
 {
  creator=&create<Value>;
 }

 template<typename OtherValue>
 Inteligent (const OtherValue& other)
 {
  creator=&create<OtherValue>;
  pointer=creator(other);
 }

 Inteligent (const Inteligent& other)
 {
  creator=other.creator;
  pointer=creator(*(other.pointer));
 }

 Inteligent (Inteligent&& other):pointer(other.pointer),creator(other.creator)
 {
  other.pointer=nullptr;
 }

 template<typename OtherValue>
 Inteligent (const Inteligent<OtherValue>& other)
 {
  creator=other.creator;
  pointer=creator(*(other.pointer));
 }

 template<typename OtherValue>
 Inteligent (Inteligent<OtherValue>&& other):pointer(other.pointer),creator(other.creator)
 {
  other.pointer=nullptr;
 }

 template<typename OtherValue>
 Inteligent&
 operator= (const Inteligent<OtherValue>& other)
 {
  if(&other!=this)
  {
   delete pointer;
   creator=other.creator;
   pointer=creator(*(other.pointer));
  }
  return *this;
 }

 Inteligent&
 operator= (const Inteligent& other)
 {
  if(&other!=this)
  {
   delete pointer;
   creator=other.creator;
   pointer=creator(*(other.pointer));
  }
  return *this;
 }

 template<typename OtherValue>
 Inteligent&
 operator= (Inteligent<OtherValue>&& other)
 {
  if(&other!=this)
  {
   delete pointer;
   creator=other.creator;
   pointer=other.pointer;
   other.pointer=nullptr;
  }
  return *this;
 }

 Inteligent&
 operator= (const Value& other)
 {
  if (pointer)
  {
   *pointer=other;
  }
  else
  {
   pointer=creator(other) ;
  }
  return *this;
 }

 ~Inteligent()
 {
  delete pointer;
  pointer=0;
 }

 Value&
 operator()()
 {
  assert (pointer);
  return *pointer;
 }

 const Value&
 operator()() const
 {
  assert (pointer);
  return *pointer;
 }

 operator Value& ()
 {
  assert (pointer);
  return *pointer;
 }

 operator const Value& () const
 {
  assert (pointer);
  return *pointer;
 }

 template<typename OtherValue>
 OtherValue& as()
 {
  return (OtherValue&) this->operator()();
 }

 template<typename OtherValue>
 const OtherValue& as() const
 {
  return (OtherValue&) this->operator()();
 }

 operator bool () const
 {
  return pointer;
 }
private:

 template<typename OtherValue>
 static Value * create(const Value& arg)
 {
     return new OtherValue((OtherValue&)arg);
 }
 typedef Value* (*CREATION)(const Value& arg);
 CREATION creator=nullptr;

public:
 template<typename OtherValue,typename ...Arguments>
 static Inteligent makeInteligent (const Arguments& ... arguments)
 {
  return Inteligent (OtherValue (arguments ...));
 }
};
struct Base
{
 int a;
 virtual void speak()
 {
  cout<<"Base"<<endl;
  cout<<"a="<<a<<endl;
 }
};

struct Derivated:Base
{
 int b;
 void speak()
 {
  cout<<"Derivated"<<endl;
  cout<<"a="<<a<<" e b="<<b<<endl;
 }
};

struct Polimorfic
{
 enum derivateds
 {
  base,
  derivated
 };

 Inteligent<Base> ibase;

 Polimorfic(const derivateds& temp)
 {
  switch (temp)
  {
   case base:
    ibase=Inteligent<Base>::makeInteligent<Base>();
    break;
   case derivated:
    ibase=Inteligent<Base>::makeInteligent<Derivated>();
    break;
  }
 }

 Base& obtain()
 {
  return ibase.operator ()();
 }

 Inteligent<Base>& inteligente()
 {
  return ibase;
 }
};

int main()
{
 Polimorfic p1(Polimorfic::base);
 Polimorfic p2(Polimorfic::derivated);
 p1.obtain().a=10;
 p2.obtain().a=20;
 p2.ibase.as<Derivated>().b=30;
 p1.obtain().speak(); 
 p2.obtain().speak(); 
 p1=p2;
 p1.obtain().speak(); 
 p2.obtain().a=33;
 p1.obtain().speak(); 
 p2.obtain().speak(); 
 return 0;
}

Why? Is the rule-of-zero just this? Am I missing something?

Aucun commentaire:

Enregistrer un commentaire