Build a wrapper-class for a pointer to pointer in c++ - c++

I am trying to create a small wrapper-class that lets me use a pointer to a pointer like
it was just a normal pointer(just for convenience).
I came up with the following code:
template<typename T>
class PtrPtr
{
public:
PtrPtr() = default;
PtrPtr(const T** ptr) : m_ptr(ptr) { }
inline void operator =(const T** ptr) { m_ptr = ptr; }
inline void operator =(T** ptr) { m_ptr = ptr; }
inline operator T*() const { return (*m_ptr); }
inline T** get() const { return m_ptr; }
private:
T** m_ptr;
};
I thought the operator inline operator T*() const { return (*m_ptr); } would
make it possible to use the class as if it were a pointer to T, however it doesn't seem to work
when I try to access T's elements with the following syntax:
PtrPtr<myStruct> ptr = function that returns a pointer to pointer to myStruct;
ptr->some member of myStruct; <-Gives an error
static_cast<myStruct*>(ptr)->some member of myStruct; <-works but obviously tedious syntax
Note that when I specifically cast "PtrPtr ptr" to a T* and then try to access its
members with the "->"-operator it seems to work.
Any Ideas if it is possible to acheive a clean syntax here?

The solution is to over load the ->-operator.
This thread explains how it is done.

Related

Pointer Constructor in C++

I'm asked to write a SmartPointer class. One of the constructors takes a pointer variable, and I assume that I should simply copy the pointer to the relevant variable. But when I try, I get a segmentation error. Here is the content of the header file and my implementation of Pointer Constructor.
class ReferenceCount {
public:
size_t AddRef() {
return ++count;
}
size_t Release() {
return --count;
}
size_t getCount() const {
return count;
}
private:
size_t count = 0; // Reference count
};
template<typename T>
class SmartPointer {
private:
void free();
// pointer to actual data
T *dataPointer;
// Reference count
ReferenceCount *referenceCount;
public:
//Constructor
SmartPointer();
// Copy constructor
SmartPointer(const SmartPointer<T> &sp);
explicit SmartPointer(T *pValue);
// Assignment operator
SmartPointer<T> &operator=(const SmartPointer<T> &sp);
SmartPointer<T> &operator=(T *pValue);
// Destructor
~SmartPointer();
T &operator*() const;
T *operator->() const;
T *get() const;
ReferenceCount *getReferenceCount() const;
};
The constructor:
template<typename T>
SmartPointer<T>::SmartPointer(T *pValue) {
dataPointer = pValue;
referenceCount = nullptr;
}
You appear to be writing something similar to shared_ptr<T>.
For a shared_ptr-like smart pointer, each smart pointer has both a pointer-to-object and a pointer-to-control-block.
When you are constructed with a pointer-to-object, you are responsible to create the control block.
In your case, your control block name is ReferenceCount.
So add a new ReferenceCount to that constructor. Probably start it off with a count of 1.

How to call implicitly constructor of value wrapped in shared_ptr which is placed in std::map collection

I'm working with code generator where I can't obtain directly classname of the value which is wrapped in shared_ptr and placed in std::map.
I came to a situation where I need to create new map object but without access to classname I can't perform a valid object constructor call. I tried with the map operator at[], which calls the value constructor, but it calls shared_ptr<T> constructor and the object inside stays uninitialized.
Here the example:
#include <iostream>
#include <map>
#include <memory>
class A
{
public:
A() { std::cout << "A"; }
int getMember() const { return m_member; }
private:
int m_member = 1;
};
int main()
{
std::map<int, A> mapIntToA;
std::map<int, std::shared_ptr<A>> mapIntToAptr;
mapIntToA[1]; // runs A constructor
std::cout << mapIntToA[1].getMember();
mapIntToAptr[1]; // runs shared_ptr constructor
// cant call methods of uninitalized object
// std::cout << mapIntToAptr[1]->getMember();
// this init works, but I can't use classname 'A' in my code generator
// mapIntToAptr[1] = std::make_shared<A>();
return 0;
}
You can use the member types of std::map and std::shared_ptr to get the type of the element.
Something like
using type = typename std::map<int, std::shared_ptr<A>>::mapped_type::element_type;
mapIntToAptr[1] = std::make_shared<type>();
mapIntToAptr.emplace(1, ::std::make_shared<decltype(mapIntToAptr)::mapped_type::element_type>());
Note that use of emplace prevents a situation when map is left with nullptr value when make_shared throws.
operator[] of std::map default constructs absent value.
So, you might wrap std::shared_ptr into a class which constructs you inner class as expected, something like:
template <typename T>
struct shared_ptr_wrapper
{
std::shared_ptr<T> data = std::make_shared<T>();
operator const std::shared_ptr<T>& () const {return data;}
operator std::shared_ptr<T>& () {return data;}
const std::shared_ptr<T>& operator ->() const { return data; }
std::shared_ptr<T>& operator ->() {return data;}
const T& operator *() const { return *data; }
T& operator *() {return *data;}
};
then
std::map<int, shared_ptr_wrapper<A>> mapIntToAptr;
mapIntToAptr[1]; // runs shared_ptr constructor
std::cout << mapIntToAptr[1]->getMember(); // Ok

Operator overloading with template question

I'm unable to recognize the following forms of operator overloading, specifically with the template parameter involved. I found this while reading an article on nullptr. I do not see these forms on cppreference overloading page either.
Can anyone explain these forms of overloading and what they are doing?
Thanks
struct nullptr_t
{
void operator&() const = delete; // Can't take address of nullptr
template<class T>
inline operator T*() const { return 0; }
template<class C, class T>
inline operator T C::*() const { return 0; }
};
nullptr_t nullptr;
Starting simpler:
struct A {
operator int() {return 3;}
};
void function() {
A aobject;
int value = aobject; //uses A::operator int()
//value is now 3
}
operator int is a curious member function that allows the struct to be converted to an int. It's very curious in that it's the only case in C++ that uses the return type in order to resolve which overloaded function to call, including that it can resolve template types.
struct A {
operator int*() {return 0;}
};
void function() {
A aobject;
int* value = aobject; //uses A::operator int()
//value now holds the value 0 (NULL)
}
This is the same thing, but now A can be converted to an int*. It is otherwise self explanatory.
struct A {
template<class T>
operator T*() { return 0; }
};
void function() {
A aobject;
short* value = aobject; //uses A::operator T*<int>()
//value now holds the value 0 (NULL)
}
By making A::operator T*() a template method, we can make our class able to be converted to a pointer to any type. This expands the options for what you can convert to. operator T C::*() { return 0; } is similar, but also allows conversion to pointers to any member of any class, which is very rare and advanced.

Propagate constness to data pointed by member variables

It is often quite confusing to C++ newcomers that const member functions are allowed to call non-const methods on objects referenced by the class (either by pointer or reference). For example, the following is perfectly correct:
class SomeClass
{
class SomeClassImpl;
SomeClassImpl * impl_; // PImpl idiom
public:
void const_method() const;
};
struct SomeClass::SomeClassImpl
{
void non_const_method() { /*modify data*/ }
};
void SomeClass::const_method() const
{
impl_->non_const_method(); //ok because impl_ is const, not *impl_
};
However, it would sometimes be rather handy if the constness would propagate to pointed objects (I voluntarily used the PImpl idiom because it is one of the case where I think "constness propagation" would be very useful).
When using pointers, this can easily be achieved by using some kind of smart pointer with operators overloaded on constness:
template < typename T >
class const_propagating_ptr
{
public:
const_propagating_ptr( T * ptr ) : ptr_( ptr ) {}
T & operator*() { return *ptr_; }
T const & operator*() const { return *ptr_; }
T * operator->() { return ptr_; }
T const * operator->() const { return ptr_; }
// assignment operator (?), get() method (?), reset() method (?)
// ...
private:
T * ptr_;
};
Now, I just need to modify SomeClass::impl_ to be a const_propagating_ptr<SomeClassImpl> to obtain the wanted behavior.
So I have a few questions about this:
Are there some issues with constness propagation that I have overlooked?
If not, are there any libraries that provide classes to obtain constness propagation?
Wouldn't it be useful that the common smart pointers (unique_ptr, shared_ptr, etc.) provide some mean to obtain this behavior (for example through a template parameter)?
As #Alf P. Steinbach noted, you oversaw the fact that copying your pointer would yield a non-const object pointing to the same underlying object. Pimpl (below) nicely circumvent the issue by performing a deep-copy, unique_ptr circumvents it by being non-copyable. It is much easier, of course, if the pointee is owned by a single entity.
Boost.Optional propagates const-ness, however it's not exactly a pointer (though it models the OptionalPointee concept). I know of no such other library.
I would favor that they provide it by default. Adding another template parameter (traits class I guess) does not seem worth the trouble. However that would radically change the syntax from a classic pointer, so I am not sure that people would be ready to embrace it.
Code of the Pimpl class
template <class T>
class Pimpl
{
public:
/**
* Types
*/
typedef T value;
typedef const T const_value;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
/**
* Gang of Four
*/
Pimpl() : _value(new T()) {}
explicit Pimpl(const_reference v) : _value(new T(v)) {}
Pimpl(const Pimpl& rhs) : _value(new T(*(rhs._value))) {}
Pimpl& operator=(const Pimpl& rhs)
{
Pimpl tmp(rhs);
swap(tmp);
return *this;
} // operator=
~Pimpl() { boost::checked_delete(_value); }
void swap(Pimpl& rhs)
{
pointer temp(rhs._value);
rhs._value = _value;
_value = temp;
} // swap
/**
* Data access
*/
pointer get() { return _value; }
const_pointer get() const { return _value; }
reference operator*() { return *_value; }
const_reference operator*() const { return *_value; }
pointer operator->() { return _value; }
const_pointer operator->() const { return _value; }
private:
pointer _value;
}; // class Pimpl<T>
// Swap
template <class T>
void swap(Pimpl<T>& lhs, Pimpl<T>& rhs) { lhs.swap(rhs); }
// Not to be used with pointers or references
template <class T> class Pimpl<T*> {};
template <class T> class Pimpl<T&> {};
One approach is to just not use the pointer directly except through two accessor functions.
class SomeClass
{
private:
class SomeClassImpl;
SomeClassImpl * impl_; // PImpl idiom - don't use me directly!
SomeClassImpl * mutable_impl() { return impl_; }
const SomeClassImpl * impl() const { return impl_; }
public:
void const_method() const
{
//Can't use mutable_impl here.
impl()->const_method();
}
void non_const_method() const
{
//Here I can use mutable_impl
mutable_impl()->non_const_method();
}
};
For the record, I just found out that the Loki library does provide a const propagating pointer (ConstPropPtr<T>). It looks just like the one in the question, except that it also deletes the wrapped pointer in its destructor, and it is used to implement a Pimpl class similar to the one proposed by #Matthieu (but not copyable).
If you think it should "propagate" const-ness, then it means you don't really believe it is a pointer (or reference), but you believe it is a container: if the value is constant when the object is constant, it's because the object contains the value.
So copying the object copies the value, at least logically (CoW).
If you insist that it is a pointer/reference IOW that you can copy the object while sharing the contained value, then you have an unsound (contradicting) interface.
Conclusion: make up your mind. It is either a container or a pointer.
A pointer does not propagate const-ness, by definition.

STL-friendly pImpl class?

I am maintaining a project that can take a considerable time to build so am trying to reduce dependencies where possible. Some of the classes could make use if the pImpl idiom and I want to make sure I do this correctly and that the classes will play nicely with the STL (especially containers.) Here is a sample of what I plan to do - does this look OK? I am using std::auto_ptr for the implementation pointer - is this acceptable? Would using a boost::shared_ptr be a better idea?
Here is some code for a SampleImpl class that uses classes called Foo and Bar:
// SampleImpl.h
#ifndef SAMPLEIMPL_H
#define SAMPLEIMPL_H
#include <memory>
// Forward references
class Foo;
class Bar;
class SampleImpl
{
public:
// Default constructor
SampleImpl();
// Full constructor
SampleImpl(const Foo& foo, const Bar& bar);
// Copy constructor
SampleImpl(const SampleImpl& SampleImpl);
// Required for std::auto_ptr?
~SampleImpl();
// Assignment operator
SampleImpl& operator=(const SampleImpl& rhs);
// Equality operator
bool operator==(const SampleImpl& rhs) const;
// Inequality operator
bool operator!=(const SampleImpl& rhs) const;
// Accessors
Foo foo() const;
Bar bar() const;
private:
// Implementation forward reference
struct Impl;
// Implementation ptr
std::auto_ptr<Impl> impl_;
};
#endif // SAMPLEIMPL_H
// SampleImpl.cpp
#include "SampleImpl.h"
#include "Foo.h"
#include "Bar.h"
// Implementation definition
struct SampleImpl::Impl
{
Foo foo_;
Bar bar_;
// Default constructor
Impl()
{
}
// Full constructor
Impl(const Foo& foo, const Bar& bar) :
foo_(foo),
bar_(bar)
{
}
};
SampleImpl::SampleImpl() :
impl_(new Impl)
{
}
SampleImpl::SampleImpl(const Foo& foo, const Bar& bar) :
impl_(new Impl(foo, bar))
{
}
SampleImpl::SampleImpl(const SampleImpl& sample) :
impl_(new Impl(*sample.impl_))
{
}
SampleImpl& SampleImpl::operator=(const SampleImpl& rhs)
{
if (this != &rhs)
{
*impl_ = *rhs.impl_;
}
return *this;
}
bool SampleImpl::operator==(const SampleImpl& rhs) const
{
return impl_->foo_ == rhs.impl_->foo_ &&
impl_->bar_ == rhs.impl_->bar_;
}
bool SampleImpl::operator!=(const SampleImpl& rhs) const
{
return !(*this == rhs);
}
SampleImpl::~SampleImpl()
{
}
Foo SampleImpl::foo() const
{
return impl_->foo_;
}
Bar SampleImpl::bar() const
{
return impl_->bar_;
}
You should consider using copy-and-swap for assignment if it's possible that Foo or Bar might throw as they're being copied. Without seeing the definitions of those classes, it's not possible to say whether they can or not. Without seeing their published interface, it's not possible to say whether they will in future change to do so, without you realising.
As jalf says, using auto_ptr is slightly dangerous. It doesn't behave the way you want on copy or assignment. At a quick look, I don't think your code ever allows the impl_ member to be copied or assigned, so it's probably OK.
If you can use scoped_ptr, though, then the compiler will do that tricky job for you of checking that it's never wrongly modified. const might be tempting, but then you can't swap.
There are a couple of problems with the Pimpl.
First of all, though not evident: if you use Pimpl, you will have to define the copy constructor / assignment operator and destructor (now known as "Dreaded 3")
You can ease that by creating a nice template class with the proper semantic.
The problem is that if the compiler sets on defining one of the "Dreaded 3" for you, because you had used forward declaration, it does know how to call the "Dreaded 3" of the object forward declared...
Most surprising: it seems to work with std::auto_ptr most of the times, but you'll have unexpected memory leaks because the delete does not work. If you use a custom template class though, the compiler will complain that it cannot find the needed operator (at least, that's my experience with gcc 3.4.2).
As a bonus, my own pimpl class:
template <class T>
class pimpl
{
public:
/**
* Types
*/
typedef const T const_value;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
/**
* Gang of Four
*/
pimpl() : m_value(new T) {}
explicit pimpl(const_reference v) : m_value(new T(v)) {}
pimpl(const pimpl& rhs) : m_value(new T(*(rhs.m_value))) {}
pimpl& operator=(const pimpl& rhs)
{
pimpl tmp(rhs);
swap(tmp);
return *this;
} // operator=
~pimpl() { delete m_value; }
void swap(pimpl& rhs)
{
pointer temp(rhs.m_value);
rhs.m_value = m_value;
m_value = temp;
} // swap
/**
* Data access
*/
pointer get() { return m_value; }
const_pointer get() const { return m_value; }
reference operator*() { return *m_value; }
const_reference operator*() const { return *m_value; }
pointer operator->() { return m_value; }
const_pointer operator->() const { return m_value; }
private:
pointer m_value;
}; // class pimpl<T>
// Swap
template <class T>
void swap(pimpl<T>& lhs, pimpl<T>& rhs) { lhs.swap(rhs); }
Not much considering boost (especially for the cast issues), but there are some niceties:
proper copy semantic (ie deep)
proper const propagation
You still have to write the "Dreaded 3". but at least you can treat it with value semantic.
EDIT: Spurred on by Frerich Raabe, here is the lazy version, when writing the Big Three (now Four) is a hassle.
The idea is to "capture" information where the full type is available and use an abstract interface to make it manipulable.
struct Holder {
virtual ~Holder() {}
virtual Holder* clone() const = 0;
};
template <typename T>
struct HolderT: Holder {
HolderT(): _value() {}
HolderT(T const& t): _value(t) {}
virtual HolderT* clone() const { return new HolderT(*this); }
T _value;
};
And using this, a true compilation firewall:
template <typename T>
class pimpl {
public:
/// Types
typedef T value;
typedef T const const_value;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
/// Gang of Five (and swap)
pimpl(): _holder(new HolderT<T>()), _p(this->from_holder()) {}
pimpl(const_reference t): _holder(new HolderT<T>(t)), _p(this->from_holder()) {}
pimpl(pimpl const& other): _holder(other->_holder->clone()),
_p(this->from_holder())
{}
pimpl(pimpl&& other) = default;
pimpl& operator=(pimpl t) { this->swap(t); return *this; }
~pimpl() = default;
void swap(pimpl& other) {
using std::swap;
swap(_holder, other._holder);
swap(_p, other._p)
}
/// Accessors
pointer get() { return _p; }
const_pointer get() const { return _p; }
reference operator*() { return *_p; }
const_reference operator*() const { return *_p; }
pointer operator->() { return _p; }
const_pointer operator->() const { return _p; }
private:
T* from_holder() { return &static_cast< HolderT<T>& >(*_holder)._value; }
std::unique_ptr<Holder> _holder;
T* _p; // local cache, not strictly necessary but avoids indirections
}; // class pimpl<T>
template <typename T>
void swap(pimpl<T>& left, pimpl<T>& right) { left.swap(right); }
I've been struggling with the same question. Here's what I think the answer is:
You can do what you are suggesting, so long as you define the copy and assignment operators to do sensible things.
It's important to understand that the STL containers create copies of things. So:
class Sample {
public:
Sample() : m_Int(5) {}
void Incr() { m_Int++; }
void Print() { std::cout << m_Int << std::endl; }
private:
int m_Int;
};
std::vector<Sample> v;
Sample c;
v.push_back(c);
c.Incr();
c.Print();
v[0].Print();
The output from this is:
6
5
That is, the vector has stored a copy of c, not c itself.
So, when you rewrite it as a PIMPL class, you get this:
class SampleImpl {
public:
SampleImpl() : pimpl(new Impl()) {}
void Incr() { pimpl->m_Int++; }
void Print() { std::cout << m_Int << std::endl; }
private:
struct Impl {
int m_Int;
Impl() : m_Int(5) {}
};
std::auto_ptr<Impl> pimpl;
};
Note I've mangled the PIMPL idiom a bit for brevity. If you try to push this into a vector, it still tries to create a copy of the SampleImpl class. But this doesn't work, because std::vector requires that the things it store provide a copy constructor that doesn't modify the thing it's copying.
An auto_ptr points to something that is owned by exactly one auto_ptr. So when you create a copy of an auto_ptr, which one now owns the underlying pointer? The old auto_ptr or the new one? Which one is responsible for cleaning up the underlying object? The answer is that ownership moves to the copy and the original is left as a pointer to nullptr.
What auto_ptr is missing that prevents its use in a vector is copy constructor taking a const reference to the thing being copied:
auto_ptr<T>(const auto_ptr<T>& other);
(Or something similar - can't remember all the template parameters). If auto_ptr did provide this, and you tried to use the SampleImpl class above in the main() function from the first example, it would crash, because when you push c into the vector, the auto_ptr would transfer ownership of pimpl to the object in the vector and c would no longer own it. So when you called c.Incr(), the process would crash with a segmentation fault on the nullptr dereference.
So you need to decide what the underlying semantics of your class are. If you still want the 'copy everything' behaviour, then you need to provide a copy constructor that implements that correctly:
SampleImpl(const SampleImpl& other) : pimpl(new Impl(*(other.pimpl))) {}
SampleImpl& operator=(const SampleImpl& other) { pimpl.reset(new Impl(*(other.pimpl))); return *this; }
Now when you try to take a copy of a SampleImpl, you also get a copy of its Impl struct, owned by the copy SampleImpl. If you're taking an object that had lots of private data members and was used in STL containers and turning it into a PIMPL class, then this is probably what you want, as it provides the same semantics as the original. But note that pushing the object into a vector will be considerably slower as there is now dynamic memory allocation involved in copying the object.
If you decide you don't want this copy behaviour, then the alternative is for the copies of SampleImpl to share the underlying Impl object. In this case, it's not longer clear (or even well-defined) which SampleImpl object owns the underlying Impl. If ownership doesn't clearly belong in one place, then std::auto_ptr is the wrong choice for storing it
and you need to use something else, probably a boost template.
Edit: I think the above copy constructor and assignment operator are exception-safe so long as ~Impl doesn't throw an exception. This should always be true of your code anyway.