Got this code (should be all that is relevant):
//movable_ptr.hpp
//Michal Cermak
#ifndef MOVABLE_H
#define MOVABLE_H
template<typename T> class movable_ptr;
template<typename T> class enable_movable_ptr {
public:
//default constructor
enable_movable_ptr() {};
enable_movable_ptr(T* p) : ptr_(p) {};
//operators...
T& operator*() const { return *ptr_; };
T* operator->() const { return ptr_; };
bool operator==(const enable_movable_ptr<T>& p) const { return p.ptr_ == ptr_; };
T* get() {return ptr_; };
private:
T* ptr_ = nullptr;
};
template<typename T> class movable_ptr {
public:
//parameterless constructor
movable_ptr() {};
//constructor from T*
movable_ptr(T* p) : ptr_(p) { add_to_tracked(this); };
//operators ...
enable_movable_ptr<T>& operator*() const { return *ptr_; };
enable_movable_ptr<T>* operator->() const { return ptr_; };
bool operator==(const movable_ptr<T>& p) const { return p.ptr_ == ptr_; };
//access to variables
enable_movable_ptr<T>* get() {return ptr_; };
void set(enable_movable_ptr<T>* p) { ptr_ = p; };
private:
enable_movable_ptr<T>* ptr_ = nullptr;
};
template<typename T> movable_ptr<T> get_movable(enable_movable_ptr<T>& p){
return new movable_ptr<T>(p);
};
#endif
My problem is that when I run the following code (or other similar ones for that matter), the movable_ptr<T> doesn't get de-referenced all the way to A, but gets stuck on enable_movable_ptr<A>, which causes comparisons and other stuff to throw errors, because "'val' is not a member of enable_movable_ptr<A>". It is a member of A though, so if I de-reference correctly, it should then work.
#include <iostream>
#include <memory>
#include <string>
#include "movable_ptr.hpp"
using namespace std;
class A : public enable_movable_ptr<A>
{
public:
int val;
A(int val) : val(val) {}
};
void test_ptr_dereference() {
A x(42);
auto px = get_movable(x);
TEST_ASSERT(&*px == &x);
TEST_ASSERT(&px->val == &x.val);
}
int main(int argc, char* argv[]) {
test_ptr_dereference();
}
I am guessing I did something wrong in the overloaded operators, but otherwise have no clue. Any ideas on how to fix it?
Related
I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class
I have to pass around the void * for supporting types that can't be known at compile time, but I also don't want to go totally insane and left everything on myself so I think to use type_info for type_Checking but since type_info doesn't support copy operation I am getting compiler errors when passing them around
#include <bits/stdc++.h>
struct PropertyClassInterface {
virtual const char * name() = 0;
virtual void set(const char * property_name,std::pair<const void *,std::type_info> new_val) = 0;
virtual std::pair<std::shared_ptr<void>,std::type_info> get(const char * property_name) = 0;
template< typename Type>
static std::pair<std::shared_ptr<void>,std::type_info> get_type_pair(const Type& Value) {
std::shared_ptr<void> t = std::make_shared<Type>();
*static_cast<Type *>(t.get()) = Value;
*return std::make_pair(t,typeid(Type));* // error
}
};
struct PropertyManager {
using base_pointer = std::shared_ptr<PropertyClassInterface>;
void add_object(base_pointer new_member) {
objects.push_back(new_member);
}
template<typename Type>
void set(const char * object_name,const char * property_name,const Type& new_val) {
find_object_orThrow(object_name)->set(property_name,std::make_pair(static_cast<const void *>(&new_val),typeid(new_val)));
}
template<typename Type>
Type get(const char * object_name, const char * property_name) {
auto a = find_object_orThrow(object_name)->get(property_name);
if (typeid(Type).hash_code() != a.second.hash_code())
throw std::runtime_error{"get(): mismatched type"};
return a.first;
}
public:
std::vector<base_pointer> objects;
base_pointer find_object_orThrow(const char * obj_name){
for(auto& o : objects) {
if (!strcmpi(o->name(),obj_name)) {
return o;
}
}
throw std::runtime_error{std::string("no object named \"") + obj_name + "\" found"};
}
};
struct testClass : PropertyClassInterface {
void set(const char * property_name,std::pair<const void *,std::type_info> new_val) {
auto checkTypeInfo = [&new_val](const std::type_info& expected) {
if (new_val.second.hash_code() != expected.hash_code())
throw std::runtime_error{"set(): wrong type"};
};
if (!strcmpi(property_name,"my_number")) {
checkTypeInfo(typeid(decltype(my_number)));
my_number = *static_cast<const decltype(my_number) *>(new_val.first);
}
};
std::pair<std::shared_ptr<void>,std::type_info> get(const char * property_name) {
if (!strcmpi(property_name,"my_number")) {
PropertyClassInterface::get_type_pair(my_number);
}
}
private:
int my_number;
};
int main() {
};
so do I have to use dynamic memory for storing type_info as well
I am limited to c++11 and I know about not using bits headers and am only using for testing
What you want to do is implement an any, or use boost any.
An any isn't hard to write.
namespace details {
struct any_concept;
using pimpl=std::unique_ptr<any_concept>;
struct any_concept {
virtual ~any_concept() {}
virtua pimpl clone() const = 0;
virtual std::type_info const& type() const = 0;
private:
virtual void* unsafe_get() = 0;
virtual void const* unsafe_get() const = 0;
public:
template<class T>
T* get() {
if (typeid(T) != type()) return nullptr;
return static_cast<T*>(unsafe_get());
}
template<class T>
T const* get() const {
if (typeid(T) != type()) return nullptr;
return static_cast<T const*>(unsafe_get());
}
};
template<class T>
struct any_model:any_concept {
T t;
virtual ~any_model() = default;
virtual pimpl clone() const final override {
return pimpl( new any_model(t) );
}
virtual std::type_info const& type() const final override {
return typeid(T);
}
template<class U>
any_model(U&& u):t(std::forward<U>(u)){}
private:
virtual void* unsafe_get() final override { return std::addressof(t); }
virtual void const* unsafe_get() const final override { return std::addressof(t); }
};
}
struct any {
template<class T, typename std::enable_if<!std::is_same<any, typename std::decay<T>::type>::value, bool> =true>
any( T&& t ):
pImpl( new details::any_model<typename std::decay<T>::type>( std::forward<T>(t) ) )
{}
template<class T>
T* get() {
if (!pImpl) return nullptr;
return pImpl->get<T>();
}
template<class T>
T const* get() const {
if (!pImpl) return nullptr;
return const_cast<details::any_concept const&>(*pImpl).get<T>();
}
template<class T>
bool contains()const { return get<T>(); }
explicit operator bool() const {
return (bool)pImpl;
}
any()=default;
any(any&&)=default;
any& operator=(any&&)=default;
~any()=default;
any(any const& o):
pImpl( o.pImpl?o.pImpl->clone():pimpl{} )
{}
any& operator=(any const& o) {
any tmp(o);
std::swap(*this, tmp);
return *this;
}
private:
details::pimpl pImpl;
};
there; a really simple any implementation. Written on a phone, so probably contains typos.
It supports value semantics, but store anything (that can be copied and destroyed). If you know what it stores, you can .get<T>() it. You can ask it if it contains<T>() as well.
This is known as a vocabulary type. It is basically your void* and type info bundled in a way that makes misuse more difficult.
I'm trying to implement a simple abstract syntax tree (AST) in C++ using the visitor pattern. Usually a visitor pattern does not handle return value. But in my AST there are expressions nodes which care about the return type and value of its children node. For example, I have a Node structure like this:
class AstNode
{
public:
virtual void accept(AstNodeVisitor&) = 0;
void addChild(AstNode* child);
AstNode* left() { return m_left; }
AstNode* right() { return m_right; }
...
private:
AstNode* m_left;
AstNode* m_right;
};
class CompareNode : public AstNode
{
public:
virtual void accept(AstNodeVisitor& v)
{
v->visitCompareNode(this);
}
bool eval(bool lhs, bool rhs) const
{
return lhs && rhs;
}
};
class SumNode : public AstNode
{
public:
virtual void accept(AstNodeVisitor& v)
{
v->visitSumNode(this);
}
int eval(int lhs, int rhs) const
{
return lhs + rhs;
}
};
class AstNodeVisitor
{
public:
...
bool visitCompareNode(CompareNode& node)
{
// won't work, because accept return void!
bool lhs = node.left()->accept(*this);
bool rhs = node.right()->accept(*this);
return node.eval(lhs, rhs);
}
int visitSumNode(Node& node)
{
// won't work, because accept return void!
int lhs = node.left()->accept(*this);
int rhs = node.right()->accept(*this);
return node.eval(lhs, rhs);
}
};
In this case both CompareNode and SumNode are binary operators but they rely on the return type of their children's visit.
As far as I can see to make it work, there are only 2 options:
accept can still return void, save the return value in a context object which is passed to each accept and visit function, and use them in the visit function, where I know what type to use. This should work but feels like a hack.
make AstNode a template, and accept function a none virtual, but return type depends on template parameter T.But if I do this, I no longer have a common AstNode* class and can't save any AstNode* in the children list.
for example:
template <typename T`>
class AstNode
{
public:
T accept(AstNodeVisitor&);
...
};
So is there a more elegant way to do this? This should be a fairly common problem for people implementing AST walking so I'd like to know what's the best practice.
Thanks.
The Visitor can have member that it can use to store result, something like:
class AstNodeVisitor
{
public:
void visitCompareNode(CompareNode& node)
{
node.left()->accept(*this); // modify b
bool lhs = b;
node.right()->accept(*this); // modify b
bool rhs = b;
b = node.eval(lhs, rhs);
}
void visitSumNode(Node& node)
{
node.left()->accept(*this); // modify n
int lhs = n;
node.right()->accept(*this); // modify n
int rhs = n;
n = node.eval(lhs, rhs);
}
private:
bool b;
int n;
};
You may also want to save the type of last result or use something like boost::variant.
template<class T> struct tag { using type=T; };
template<class...Ts> struct types { using type=types; }
template<class T>
struct AstVisitable {
virtual boost::optional<T> accept( tag<T>, AstNodeVisitor&v ) = 0;
virtual ~AstVisitable() {};
};
template<>
struct AstVisitable<void> {
virtual void accept( tag<void>, AstNodeVisitor&v ) = 0;
virtual ~AstVisitable() {};
};
template<class Types>
struct AstVisitables;
template<>
struct AstVisibables<types<>> {
virtual ~AstVisitables() {};
};
template<class T0, class...Ts>
struct AstVisitables<types<T0, Ts...>>:
virtual AstVisitable<T0>,
AstVisitables<types<Ts...>>
{
using AstVisitable<T0>::accept;
using AstVisitables<types<Ts...>>::accept;
};
using supported_ast_return_types = types<int, bool, std::string, void>;
class AstNode:public AstVisitables<supported_ast_return_types> {
public:
void addChild(AstNode* child);
AstNode* left() { return m_left.get(); }
AstNode* right() { return m_right.get(); }
private:
std::unique_ptr<AstNode> m_left;
std::unique_ptr<AstNode> m_right;
};
template<class types>
struct AstVisiablesFailAll;
template<>
struct AstVisiablesFailAll<> {
virtual ~AstVisiablesFailAll() {};
};
template<class T>
struct AstVisitableFailure : virtual AstVisitable<T> {
boost::optional<T> accept( tag<T>, AstNodeVisitor& ) override {
return {};
}
};
template<>
struct AstVisitableFailure<void> : virtual AstVisitable<void> {
void accept( tag<void>, AstNodeVisitor& ) override {
return;
}
};
template<class T0, class...Ts>
struct AstVisitablesFailAll<types<T0, Ts...>>:
AstVisitableFailure<T0>,
AstVisitableFailAll<types<Ts...>>
{
using AstVisitableFailure<T0>::accept;
using AstVisitableFailAll<types<Ts...>>::accept;
};
So now you can boost::optional<bool> lhs = node.left()->accept( tag<bool>, *this );, and from the state of lhs know if the left node can be evaluated in a bool context.
SumNode looks like this:
class SumNode :
public AstNode,
AstVisiablesFailAll<supported_ast_return_types>
{
public:
void accept(tag<void>, AstNodeVisitor& v) override
{
accept(tag<int>, v );
}
boost::optional<int> accept(tag<int>, AstNodeVisitor& v) override
{
return v->visitSumNode(this);
}
int eval(int lhs, int rhs) const {
return lhs + rhs;
}
};
and visitSumNode:
boost::optional<int> visitSumNode(Node& node) {
// won't work, because accept return void!
boost::optional<int> lhs = node.left()->accept(tag<int>, *this);
boost::optional<int> rhs = node.right()->accept(tag<int>, *this);
if (!lhs || !rhs) return {};
return node.eval(*lhs, *rhs);
}
The above assumes that visiting a+b in a void context is acceptable (like in C/C++). If it isn't, then you need a means for void visit to "fail to produce a void".
In short, accepting requires context, which also determines what type you expect. Failure is an empty optional.
The above uses boost::optional -- std::experimental::optional would also work, or you can roll your own, or you can define a poor man's optional:
template<class T>
struct poor_optional {
bool empty = true;
T t;
explicit operator bool() const { return !empty; }
bool operator!() const { return !*this; }
T& operator*() { return t; }
T const& operator*() const { return t; }
// 9 default special member functions:
poor_optional() = default;
poor_optional(poor_optional const&)=default;
poor_optional(poor_optional const&&)=default;
poor_optional(poor_optional &&)=default;
poor_optional(poor_optional &)=default;
poor_optional& operator=(poor_optional const&)=default;
poor_optional& operator=(poor_optional const&&)=default;
poor_optional& operator=(poor_optional &&)=default;
poor_optional& operator=(poor_optional &)=default;
template<class...Ts>
void emplace(Ts&&...ts) {
t = {std::forward<Ts>(ts)...};
empty = false;
}
template<class...Ts>
poor_optional( Ts&&... ts ):empty(false), t(std::forward<Ts>(ts)...) {}
};
which sucks, because it constructs a T even if not needed, but it should sort of work.
For completion sake I post the template version that is mentioned by the OP
#include <string>
#include <iostream>
namespace bodhi
{
template<typename T> class Beignet;
template<typename T> class Cruller;
template<typename T> class IPastryVisitor
{
public:
virtual T visitBeignet(Beignet<T>& beignet) = 0;
virtual T visitCruller(Cruller<T>& cruller) = 0;
};
template<typename T> class Pastry
{
public:
virtual T accept(IPastryVisitor<T>& visitor) = 0;
};
template<typename T> class Beignet : public Pastry<T>
{
public:
T accept(IPastryVisitor<T>& visitor)
{
return visitor.visitBeignet(*this);
}
std::string name = "Beignet";
};
template<typename T> class Cruller : public Pastry<T>
{
public:
T accept(IPastryVisitor<T>& visitor)
{
return visitor.visitCruller(*this);
}
std::string name = "Cruller";
};
class Confectioner : public IPastryVisitor<std::string>
{
public:
virtual std::string visitBeignet(Beignet<std::string>& beignet) override
{
return "I just visited: " + beignet.name;
}
virtual std::string visitCruller(Cruller<std::string>& cruller) override
{
return "I just visited: " + cruller.name;
}
};
}
int main()
{
bodhi::Confectioner pastryChef;
bodhi::Beignet<std::string> beignet;
std::cout << beignet.accept(pastryChef) << "\n";
bodhi::Cruller<std::string> cruller;
std::cout << cruller.accept(pastryChef) << "\n";
return 0;
}
Every pastry is a node and every visitor can implement its accepted return type. Having multiple visitor could visit the same pastry.
unique_ptr is quite useful. However, it is not copyable. If virutal clone (deep copy) methods are provided for its pointed class, I think it will become more useful. Is it necessary or any better way to implement it? Any similar smart pointer exist in some library? Here is a version
template<class T>
class deep_ptr: private unique_ptr<T>
{
public:
using unique_ptr<T>::operator *;
using unique_ptr<T>::operator ->;
using unique_ptr<T>::operator bool;
using unique_ptr<T>::release;
using unique_ptr<T>::reset;
using unique_ptr<T>::get;
// add (DEFAULT_CONSTRUCTOR)(MOVE_CONSTRUCTOR)(MOVE_ASSIGNMENT_METHOD) ...
explicit deep_ptr(T* p) : unique_ptr(p) {}
deep_ptr(deep_ptr const& r) : unique_ptr(r->clone()) {}
deep_ptr& operator=(deep_ptrconst& r)
{ if (this != &r) reset(r->clone()); return *this; }
};
Juse feel it is very useful but never see similar things. ???
Unless I am misunderstanding what you are looking for, if a class has a clone method, that should be sufficient to get what you are looking for.
Sample code:
#include <iostream>
#include <memory>
struct A
{
virtual ~A() {}
virtual A* clone() = 0;
};
struct B : A
{
B(int in = 0) : x(in) {}
B(B const& copy) : x(copy.x) {}
virtual ~B() {std::cout << "In B::~B()\n";}
virtual A* clone() { return new B(*this); }
int x;
};
int main()
{
std::unique_ptr<A> p1(new B(10));
std::unique_ptr<A> p2(p1->clone());
return 0;
}
Output from running the above program:
In B::~B()
In B::~B()
Without a clone method (just a copy-constructor) the following should work:
template <typename T>
class deep_ptr
{
public:
deep_ptr() : i_() {}
deep_ptr(std::nullptr_t) : i_(nullptr) {}
template <typename U>
deep_ptr(U* u) : i_(u ? new inner_impl<U>(*u) : nullptr) {}
~deep_ptr() { delete i_; }
deep_ptr(const deep_ptr& p) : i_(p.i_ ? p.i_->copy() : nullptr) {}
deep_ptr& operator=(const deep_ptr& p)
{
if (!p.i_) { i_ = nullptr; }
else { i_ = p.i_->copy(); }
}
deep_ptr(deep_ptr&& p) : i_(p.i_) { p.i_ = nullptr; }
deep_ptr& operator=(deep_ptr&& p)
{
i_ = p.i_;
p.i_ = nullptr;
}
const T* operator->() const { return get(); }
const T* get() const
{
if (i_) { return *i_; }
return nullptr;
}
const T& operator*() const { return *static_cast<T*>(*i_); }
T* operator->() { return get(); }
T* get()
{
if (i_) { return *i_; }
return nullptr;
}
T& operator*(){ return *static_cast<T*>(*i_); }
private:
struct inner
{
virtual inner* copy() const = 0;
virtual operator const T*() const = 0;
virtual operator T*() = 0;
virtual ~inner() {}
};
inner* i_;
template <typename U>
struct inner_impl : inner
{
inner_impl(const U& u) : u_(u) {}
inner_impl* copy() const override { return new inner_impl(u_); }
operator const T*() const override { return &u_; }
operator T*() override { return &u_; }
U u_;
};
};
My abstract Reference counter class:
template<class T>
class ReferenceCounter
{
public:
ReferenceCounter();
~ReferenceCounter();
void addRef();
void release();
uint32 getCountReferences() const;
protected:
int32* pCountReferences;
virtual void destroyObject() = 0;
virtual void shallowCopy(const T& rhs) = 0;
};
template<class T>
inline ReferenceCounter<T>::ReferenceCounter()
{
pCountReferences = new int32;
*pCountReferences = 1;
}
template<class T>
inline ReferenceCounter<T>::~ReferenceCounter()
{
if(pCountReferences != NULL && *pCountReferences == 0)
{
delete pCountReferences;
pCountReferences = NULL;
}
}
template<class T>
inline void ReferenceCounter<T>::addRef()
{
debug_assert((*pCountReferences) >= 0, "Incorrect value of count references");
++(*pCountReferences);
}
template<class T>
inline void ReferenceCounter<T>::release()
{
debug_assert((*pCountReferences) > 0, "Incorrect value of count references");
(*pCountReferences)--;
if(pCountReferences != NULL && *pCountReferences == 0)
{
destroyObject();
}
}
template<class T>
inline uint32 ReferenceCounter<T>::getCountReferences() const
{
return *pCountReferences;
}
This is my smart pointer :
template<class T>
class SmartPtr
{
public:
SmartPtr();
SmartPtr(T* pInst);
SmartPtr(const SmartPtr<T>& rhs);
~SmartPtr();
void operator = (const SmartPtr<T>& rhs);
T* operator -> () const;
T* getData() const;
bool isNULL() const;
private:
T* pInst;
};
template<class T>
SmartPtr<T>::SmartPtr() : pInst(NULL) {}
template<class T>
SmartPtr<T>::SmartPtr(T* pInst) : pInst(pInst) {}
template<class T>
SmartPtr<T>::~SmartPtr()
{
if(pInst != NULL)
{
pInst->release();
}
}
template<class T>
SmartPtr<T>::SmartPtr(const SmartPtr<T>& rhs)
{
this->pInst = rhs.pInst;
if(pInst != NULL)
{
pInst->addRef();
}
}
template<class T>
void SmartPtr<T>::operator= (const SmartPtr<T>& rhs)
{
this->pInst = rhs.pInst;
if(pInst != NULL)
{
pInst->addRef();
}
}
template<class T>
T* SmartPtr<T>::operator->() const
{
return pInst;
}
template<class T>
T* SmartPtr<T>::getData() const
{
return pInst;
}
template<class T>
bool SmartPtr<T>::isNULL() const
{
return pInst == NULL;
}
There are test of code :
#include <iostream>
#include "ReferenceCounter.h"
#include "SmartPtr.h"
using namespace std;
class B;
class A : public ReferenceCounter<A>
{
public:
A();
A(const A& rhs);
~A();
SmartPtr<B> getB();
void operator = (const A& rhs);
private:
void destroyObject();
void shallowCopy(const A& rhs);
};
class B : public ReferenceCounter<B>
{
private:
void destroyObject() {} ;
void shallowCopy(const B& rhs) {};
};
A::A()
{
cout << "Create object" << endl;
}
A::A(const A& rhs)
{
shallowCopy(rhs);
addRef();
cout << "copy constructor " << endl;
}
A::~A()
{
release();
}
void A::destroyObject()
{
cout << "destroy" << endl;
}
void A::shallowCopy(const A& rhs)
{
this->pCountReferences = rhs.pCountReferences;
}
void A::operator = (const A& rhs)
{
shallowCopy(rhs);
addRef();
cout << "operator = " << endl;
}
SmartPtr<B> A::getB()
{
return SmartPtr<B>(new B());
}
SmartPtr<A> getA()
{
SmartPtr<A> a(new A());
return a;
}
int main()
{
getA();
return 0;
}
This code is worked but below not called copy constructor of smart pointer when i debug this code . What problems happens below ??
int main()
{
A a;
a.getB();
}
See here for Return value optimization.
The compiler is allowed, to eliminate the copy of a temporary object being returned.
With C++11, there's also the possibility of moving an object. See What are move semantics? for an explanation.
Update:
This is not a problem at all, just a compiler optimization.
As long as there's nothing special going on in your constructor and destructor, there's no need to prevent this optimization. You should allow this instead, because it makes your program run faster by skipping one constructor and one destructor call.