how do I tell an array pointer from a regular pointer - c++

I'm writing a smart pointer like std::shared_ptr since my compiler does not support c++17 and later versions, and I want to support array pointer like:
myptr<char []>(new char[10]);
well, it went actually well, until I got the same problem as old-version std::shared_ptr got:
myptr<char []>(new char);
yeah, it can't tell whether it's a regular pointer or an array pointer, and since my deleter is kind of like:
deleter = [](T *p) {delete[] p;}
which means it just meets the same problem that the old-version std::shared_ptr has.
my array-pointer partial specialization is like:
template <typename T, typename DeleterType>
class myptr<T[], DeleterType> { // DeleterType has a default param in main specialization
// as std::function<void(T*)>
private:
my_ptr_cnt<T, DeleterType> *p; // this is the actual pointer and count maintain class
public:
// constructor
/// \bug here:
my_ptr(T *p, DeleterType deleter=[](T *p) {delete []p;}) :
p(new my_ptr_cnt<T, DeleterType>(p, deleter)) { }
}

You can't. This is one of the many reasons that raw arrays are bad.
What you can do is forbid construction from raw pointer, and rely on make_shared-like construction.

Related

Is std::optional<std::shared_ptr<MyClass>> good for avoiding null point deference?

I want to write safe C++ programs, therefore:
I wanted to avoid memory leaks, so I started using std::shared_ptr.
However, I still had some null pointer deferences some times. I've come up with the idea of using using MyClassSafe = std::optional<std::shared_ptr<MyClass>>.
Then I avoid both memory leaks and null pointer deference. Well, kind of. For example:
MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
//use it here
} else {
//do something in case no value
}
//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
//use it here, for example:
//this deferences a nullptr
myClassSafe.value()->someFunction();
} else {
//do something in case no value
}
so this is not much safer. It's better but I still can make mistakes.
I can imagine a safe_shared_ptr<T> class that instead of calling the object's functions on operator->, it could return std::optional<T&> (much like Rust) for which we can then safely call or deal with the std::nullopt case. Isn't there something already in C++? Or can it be implemented easily?
You haven't shown need for either pointers or optionals here.
MyClass myClassSafe;
myClassSafe.someFunction();
No possibility of null pointers or empty optionals in sight.
optional<T> allows you to handle the "no T available" case, which shared_ptr<T> already handles. Therefore optional<shared_ptr<T>> is redundant, just like optional<optional<T>> is.
There is a case to be made for shared_ptr<optional<T>> - if one owner creates the T object, the other owner can see the new object, so that isn't really redundant.
Your use of std::optional here is the cause of the problem. std::shared_ptr defines operator bool as a null pointer check, but because you have wrapped it in std::optional this never gets called
If instead you try:
MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
// std::shared_ptr implements operator bool as a null pointer check
myClass->someFunction();
} else {
//do something in case no value
}
Isn't there something already in C++?
There is nothing in std to handle non null smart pointer.
As Caleth shows in his answer, you can use object directly and avoid (smart) pointer and std::optional.
Or can it be implemented easily?
Non null smart pointer (a "smart reference" :) ) should be non default constructible, and "non-movable" (I mean move should not invalidate the reference).
You could implement it with existing smart pointer, something like:
template <typename T>
class unique_ref
{
public:
// Avoid variadic constructor which might take precedence over regular copy/move constructor
// so I use tag std::in_place_t here.
template <typename ... Ts>
unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}
unique_ref(const unique_ref&) = delete;
unique_ref(unique_ref&&) = delete;
unique_ref& operator=(const unique_ref&) = delete;
unique_ref& operator=(unique_ref&&) = delete;
const T& operator*() const { return *ptr; }
T& operator*() { return *ptr; }
const T* operator ->() const { return ptr.get(); }
T* operator*() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
return {std::in_place, std::forward<Ts>(args)...};
}
unique version is not much useful, as non-copyable, non-movable. using directly T seems simpler.
shared version is copyable (its move should do identical to the copy)
A weak version might return an std::optional<shared_ref<T>>.

How to make a deep-const pointer

Let's say I want to represent a binary tree in C++. Usually, I want a Node struct like this:
struct Node {
Node* left
Node* right;
};
(Here I use struct and raw pointers just for simplicity. I know I should use smart pointers for memory management.)
This representation has a problem: I can never have a deep-const tree. (Correct me if I can.) I may mark a single Node const, but its children is hard-coded as non-const in the Node struct.
(I may use some template hack to make left and right optionally const, but this makes the const Node and non-const Node incompatible.)
Soon I found out, if I magically had some deep-const pointer (say deep_const_pointer, which makes constness transitive), I can use that pointer in Node so that having a const node automatically means having a const sub-tree.
I tried to write a deep-const pointer class, and here is what I end up with:
template <typename T>
class deep_const_pointer {
public:
explicit deep_const_pointer(const T* p_)
: p{const_cast<T*>(p_)} {}
const T& operator*() const { return *p; }
T& operator*() { return *p; }
const T* operator->() const { return p; }
T* operator->() { return p; }
// etc.
private:
T* p;
};
Here I cast out the const in the constructor and optionally add it back according to the constness of this pointer-like object. However, this implementation allows the following:
const int i = 42;
deep_const_pointer<int> p{&i};
*p = 0; // Oops!
So it depends on the user to correctly mark whether the pointer is const or not.
How should I build a deep-const pointer class? Ideally, I want the const check happen at compile-time, and that pointer class takes as much memory as a raw pointer. (Which rules out the solution to save the constness to a bool member variable and check on each access.)
EDIT: I checked std::experimental::propagate_const, and it is indeed not a "deep-const" pointer from my perspective. What I meant by deep-const pointer P is:
Constant P is pointer-to-const;
Mutable P is pointer-to-mutable;
A const reference to a non-const P is treated as if it were a const P;
Since pointer-to-const has value semantics, a const P should be trivially copyable.
propagate_const fails to match the requirement because:
It never accepts a pointer-to-const;
It is not copyable (copy constructors explicitly deleted);
From the comments and answer I received, I guess such a P is not implementable in C++.
Writing a transitive-const smart pointer is a solved problem, just look up std::experimental::propagate_const<>. It shouldn't be too hard to find appropriate implementations.
In your own try, you got constructing from a raw pointer wrong. You should not add const to the pointee-type, nor strip it out with a cast.
Fixed:
explicit deep_const_pointer(T* p_)
: p{p_} {}

unique_ptr and pointer by reference argument type

I have code where I am trying to pass the underlying pointer of a unique_ptr in to a method accepting a pointer by reference:
unique_ptr<A> a;
func(a.get());
to call:
void func(A*& a){ // I am modifying what `a` points to in here
}
but I am getting compiler errors because get() is not returning what I expected was just the raw pointer. Is it possible to achieve what I am trying to do here?
No, and that's a good thing.
The problem is that get() returns an rvalue, not a reference to unique_ptr's internal pointer. Therefore you can't modify it. If you could, you would completely mess up unique_ptr's internal state.
Just pass a reference to the unique_ptr itself if you want to modify it.
A function that takes a pointer by reference is strongly hinting that it may reallocate/delete the pointer in question. That means it is asking for ownership responsibilities. The only safe way to call such a function is to release the pointer from the unique pointer and (possibly) reacquire it after the call.
// a currently manages (owns) the pointer
std::unique_ptr<A> a;
// release ownership of internal raw pointer
auto raw = a.release();
// call function (possibly modifying raw)
func(raw);
// (re)claim ownership of whatever func() returns
a.reset(raw);
But that can still be problematic if (say) the unique_ptr has a special deleter and the function doesn't re-allocate the object accordingly. Also if the function deletes the pointer without setting it to nullptr you will have a problem.
Here is an idea:
template<typename T> struct raw_from_ptr {
raw_from_ptr(T& pointer) : _pointer(pointer), _raw_pointer(null_ptr) {}
~raw_from_ptr() {
if (_raw_pointer != null_ptr)
_pointer.reset(_raw_pointer);
}
raw_from_ptr(pointer_wrapper&& _other) : _pointer(_other._pointer) {
std::swap(_raw_pointer, _other._raw_pointer);
}
operator typename T::pointer*() && { return &_raw_pointer; }
operator typename T::pointer&() && { return _raw_pointer; }
private:
T& _pointer;
typename T::pointer _raw_pointer;
};
template<typename T> raw_from_ptr<T> get_raw_from_ptr(T& _pointer) {
return raw_from_ptr<T>(_pointer);
}
Usage:
unique_ptr<A> a;
func(get_raw_from_ptr(a));

Copy data from a pointer or chain of pointers (Object pointer, templates)

How the push_back of stl::vector is implemented so it can make copy of any datatype .. may be pointer, double pointer and so on ...
I'm implementing a template class having a function push_back almost similar to vector. Within this method a copy of argument should be inserted in internal allocated memory.
In case the argument is a pointer or a chain of pointers (an object pointer); the copy should be made of actual data pointed. [updated as per comment]
Can you pls tell how to create copy from pointer. so that if i delete the pointer in caller still the copy exists in my template class?
Code base is as follows:
template<typename T>
class Vector
{
public:
void push_back(const T& val_in)
{
T a (val_in); // It copies pointer, NOT data.
m_pData[SIZE++] = a;
}
}
Caller:
// Initialize my custom Vector class.
Vector<MyClass*> v(3);
MyClass* a = new MyClass();
a->a = 0;
a->b = .5;
// push MyClass object pointer
// now push_back method should create a copy of data
// pointed by 'a' and insert it to internal allocated memory.
// 'a' can be a chain of pointers also.
// how to achieve this functionality?
v.push_back(a);
delete a;
I can simply use STL vector to accomplish the tasks but for experiment purposes i'm writing a template class which does exactly the same.
Thanks.
if you have polymorphic object ( the pointed object may be more specialized than the variable ), I suggest you creating a virtual method called clone() that allocate a new pointer with a copy of your object:
Base* A::clone() {
A* toReturn = new A();
//copy stuff
return toReturn;
}
If you can't modify your Base class, you can use RTTI, but I will not approach this solution in this answer. ( If you want more details in this solution, please make a question regarding polymorphic cloning with RTTI).
If you have not a polymorphic object, you may allocate a new object by calling the copy constructor.
void YourVector::push_back(Base* obj) {
Base* copy = new Base(obj);
}
But it smells that what you are really needing is shared_ptr, avaliable in <tr1/memory> ( or <memory> if you use C++0x ).
Update based on comments
You may also have a two template parameters list:
template <typename T>
struct CopyConstructorCloner {
T* operator()(const T& t) {
return new T(t);
}
}
template <typename T, typename CLONER=CopyConstructorCloner<T> >
class MyList {
CLONER cloneObj;
public:
// ...
void push_back(const T& t) {
T* newElement = cloneObj(t);
// save newElemenet somewhere, dont forget to delete it later
}
}
With this approach it is possible to define new cloning politics for things like pointers.
Still, I recommend you to use shared_ptrs.
I think for this kind of problems it is better to use smart pointers ex: boost::shared_ptr or any other equivalent implementation.
There is no need to call new for the given datatype T. The push_back implementation should (must) call the copy-constructor or the assignment operator. The memory should have been allocated to hold those elemnets that are being pushed. The intial memory allocation should not call CTOR of type T. Something like:
T* pArray;
pArray = (T*) new BYTE[sizeof(T) * INITIAL_SIZE);
And then just put new object into pArray, calling the assignment operator.
One solution is to make a copy construction:
MyClass *p = new MyClass();
MyVector<MyClass*> v;
v.push_back(new MyClass(*p));
Update: From you updated question, you can definitely override push_back
template<typename T>
class MyVector {
public:
void push_back (T obj); // general push_back
template<typename TYPE> // T can already be a pointer, so declare TYPE again
void push_back (TYPE *pFrom)
{
TYPE *pNew = new TYPE(*pFrom);
// use pNew in your logic...
}
};
Something like this:
template<typename T>
class MyVector
{
T* data; // Pointer to internal memory
size_t count; // Number of items of T stored in data
size_t allocated; // Total space that is available in data
// (available space is => allocated - count)
void push_back(std::auto_ptr<T> item) // Use auto pointer to indicate transfer of ownership
/*void push_back(T* item) The dangerous version of the interface */
{
if ((allocated - count) == 0)
{ reallocateSomeMemory();
}
T* dest = &data[count]; // location to store item
new (dest) T(*item); // Use placement new and copy constructor.
++count;
}
// All the other stuff you will need.
};
Edit based on comments:
To call it you need to do this:
MyVector<Plop> data;
std::auto_ptr<Plop> item(new Plop()); // ALWAYS put dynamically allocated objects
// into a smart pointer. Not doing this is bad
// practice.
data.push_back(item);
I use auto_ptr because RAW pointers are bad (ie in real C++ code (unlike C) you rarely see pointers, they are hidden inside smart pointers).

Smart pointers and polymorphism

I implemented reference counting pointers (called SP in the example) and I'm having problems with polymorphism which I think I shouldn't have.
In the following code:
SP<BaseClass> foo()
{
// Some logic...
SP<DerivedClass> retPtr = new DerivedClass();
return retPtr;
}
DerivedClass inherits from BaseClass. With normal pointers this should have worked, but with the smart pointers it says "cannot convert from 'SP<T>' to 'const SP<T>&" and I think it refers to the copy constructor of the smart pointer.
How do I allow this kind of polymorphism with reference counting pointer?
I'd appreciate code samples cause obviously im doing something wrong here if I'm having this problem.
PS: Please don't tell me to use standard library with smart pointers because that's impossible at this moment.
Fairly obvious:
SP<DerivedClass> retPtr = new DerivedClass();
should be:
SP<BaseClass> retPtr = new DerivedClass();
You should add implicit converting constructor for SP<T>:
template<class T>
struct SP {
/// ......
template<class Y>
SP( SP <Y> const & r )
: px( r.px ) // ...
{
}
//....
private:
T * px;
}
Why not add a template assignment operator:
template <class Base>
class SP
{
...
template<class Derived>
operator = (SP<Derived>& rhs)
{
...
(and maybe copy constructor, too)?
In addition to the copy constructor:
SP(const SP<T>& ref);
you need a conversion constructor:
template<typename T2>
SP(const SP<T2>& ref);
Otherwise, the compiler will not know how to construct SP<BaseClass> from a SP<DerivedClass>; for him, they are unrelated.
The conversion constructor is fairly trivial, since internally you can convert *DerivedClass to *BaseClass automatically. Code may be very similar to that for the copy constructor.