I'm trying to implement my own allocator, which should work with STL containers and use a custom fancy pointer implementation.
I'm pretty sure, that my classes fulfill all requirements (according to cppreference) but my implementation doesn't compile for std::list because there is no conversion from my fancy pointer to a normal pointer.
A minimal example which shows the problem, (but is obviously not my real implementation):
fancy_ptr.h:
#include <cstddef>
template<typename T>
class FancyPtr {
T *ptr;
FancyPtr(T *ptr, bool) : ptr(ptr) {}; //Bool to be non standart
public:
using element_type = T;
FancyPtr(std::nullptr_t n) : FancyPtr() {};
template<class S>
operator FancyPtr<S>() {
return {ptr};
}
T &operator*() { return *ptr; }
T &operator[](size_t n) { return ptr[n]; }
T *operator->() { return ptr; }
bool operator==(const FancyPtr &other) { return ptr == other.ptr; };
static FancyPtr pointer_to(element_type &r) { return FancyPtr(&r, false); };
};
TrivialAllocator.h:
#include "fancy_ptr.h"
template<typename T>
class TrivialAllocator {
public:
using pointer = FancyPtr<T>;
using value_type = T;
TrivialAllocator() = default;
template<typename Other>
TrivialAllocator(const TrivialAllocator<Other> &other) {};
template<typename Other>
TrivialAllocator(TrivialAllocator<Other> &&other) {};
TrivialAllocator(TrivialAllocator &alloc) = default;
pointer allocate(size_t n) { return pointer::pointer_to(*new T[n]); }
void deallocate(pointer ptr, size_t n) { delete[] &*ptr; };
bool operator==(const TrivialAllocator &rhs) const { return true; };
bool operator!=(const TrivialAllocator &rhs) const { return false; };
};
main.cpp:
#include "TrivialAllocator.h"
#include <list>
int main() {
struct Test {};
using AllocT = std::allocator_traits<TrivialAllocator<long double>>;
static_assert(std::is_same_v<FancyPtr<long double>,std::pointer_traits<AllocT::pointer>::pointer>);
static_assert(std::is_same_v<FancyPtr<Test>, std::pointer_traits<AllocT::pointer>::rebind<Test>>);
std::list<long double, AllocT::allocator_type> list;
}
The static assertions are ok.
Can anybody tell me what I have to to to get this working?
PS: I know that operator-> is in something like a conversion operator, but the underlying problem is that std::list seem not to save my fancy pointers, but raw pointers.
Your class does not fulfil all the requirements.
Your pointer type must be a Cpp17RandomAccessIterator (operator++, operator+=, operator+, operator--, operator-, operator-=, operator!=, operator<, operator>=, operator<=)
Your FancyPtr<void> (which would be std::allocator_traits<TrivialAllocator<T>>::void_pointer) does not compile because of the operator[] and pointer_to(void&) (void_pointer and const_void_pointer don't need to be random access iterators)
You can't convert from a pointer to a void_pointer (You need to change your conversion operator to return {static_cast<S*>(ptr);}, or have the static_cast on a constructor of void_pointer)
You can't convert from your pointer type to bool which is one of the requirements for NullablePointer.
Your allocators's allocate and deallocate shouldn't call constructors or destructors.
However, even after making it a valid pointer type for an allocator, you still run into issues with how libstdc++ and libc++ deals with pointers. At some points in the code, there is a cast from FancyPtr<ListNode> to FancyPtr<ListNodeBase>, where ListNode derives from ListNodeBase. This is not part of the requirements of a pointer type, but is used by the implementation of std::list in those standard libraries anyways. You allow this by having operator FancyPtr<T> for any T, which is used. The standard libraries may be able to fix this by converting to a void pointer then to the base class, if the node classes are standard layout.
libstdc++ also internally uses raw T* pointers everywhere, so there are points where it implicitly tries to convert from T* to FancyPtr<T>. Unfortunately, the only way to support this would be to have a public FancyPtr(T*) constructor and a conversion to a raw pointer operator T*(). libstdc++ could fix this without breaking ABI by using p ? std::pointer_traits<pointer>::pointer_to(*p) : pointer(nullptr) to convert a T* p to a fancy pointer, and std::to_address for the reverse.
Microsoft's STL's std::list has no problems with a valid pointer type.
Here is a example implementation of a fancy pointer type that fulfils the requirements and has the workarounds for the 2 standard library implementations mentioned here: https://godbolt.org/z/vq9cvW
After some digging into the problem, I guess this is simply impossible due to libstdc++ internal limitations. This is a known old bug, "Node-based containers don't use allocator's pointer type internally":
Container nodes are linked together by built-in pointers, but they should use the allocator's pointer type instead. Currently I think only std::vector does this correctly. ...
It should work with Clang and libc++ (use -stdlib=libc++ command line option) with a couple of fixes:
FancyPtr<void>::pointer_to(...) should be a valid member function. Now it is not, because void& does not exist.
FancyPtr should provide operator!=(...) member function.
These fixes are needed to make your code at least compilable. Whether it will work correctly is out of scope of this answer.
Related
Let a polymorphic Base class have a pure virtual method insert on a stl container member (vector in this case). The function should be able to take iterator of containers like set, vector, list etc, but also take into account the type of reference (move semantics)
The pure virtual nature of the function make using template functions impossible. Afaik iterators of stl containers are separate type, thats why templates are useful. However the polymorphism is necessary. Also I noticed that there is std::move_iterator which is able to encapsulate all types of iterators.
Are there other "iterator wrappers" which I can use to define a pure virtual method in Base which takes all sorts of iterators and also acts like perfectly forwarding function template such that clients can pass iterators and move iterators?
Before introducing polymorphism the function was like this:
vector<Class> v;
template<typename Iter>
void insert(Iter begin, Iter end) {
v1.insert(begin, end, std::end(v));
}
but now there derived classes which behave slightly different on insert (mutexes, notify observers etc). It would be nice to have something like the following:
vector<Class> v;
virtual void Base::insert(GenericIter begin, GenericIter end) = 0;
[…]
void DerivedMT::insert(GenericIter begin, GenericIter end) override
{
mutex.lock();
v1.insert(begin, end, std::end(v));
mutex.unlock();
}
[…]
void DerivedObserved::insert(GenericIter begin, GenericIter end) override
{
v1.insert(begin, end, std::end(v));
notifyObservers();
}
You can't accept all the various iterators and maintain runtime polymorphism because you would then violate Liskov Substitution Principle. That is, a polymorphic bidirectional iterator will not work with wrapped forward iterator, since the latter can only be incremented. Also there are sorted associative containers, whose iterators you can not use for sorting, etc:
in case an implementor would want not to skip, but to sort the elements
in case an implementor would want to do a particular kind of search
So, the intent of a template iterator for a function is to provide a freedom for an interface implementor to do whatever he desires given he has two iterators. But with runtime polymorphic iterators you are limiting the implementor (you kind of should).
So there are two ways:
Naive. Just declare your interface with insert(std::vector<YourType>). This will handle for your all the generic iterators you want, and an implementor is free to do whatever he desires with the range.
Implement const PolymorphicForwardIterator using traits for a Forward Iterator and type erasure.
Here is an example of how you can erase a type without heap allocations:
class PolymorphicReference final
{
public:
template <typename RefT>
explicit PolymorphicReference(RefT &ref)
: pVTable_(std::addressof(GetVTable(ref))),
ref_(std::addressof(ref))
{}
void Say(const std::string& msg)
{
pVTable_->pSay(ref_, msg);
}
int Number() const
{
return pVTable_->pNumber(ref_);
}
private:
struct VTable
{
virtual void pSay(void *pRef, const std::string& msg) = 0;
virtual int pNumber(const void *pRef) = 0;
protected:
~VTable() = default;
};
template <typename RefT>
static VTable &GetVTable(const RefT&)
{
struct : VTable
{
void pSay(void *pRef, const std::string& msg) override
{
static_cast<RefT*>(pRef)->Say(msg);
}
int pNumber(const void *pRef) override
{
return static_cast<const RefT*>(pRef)->Number();
}
} static vTable;
return vTable;
}
private:
VTable *pVTable_;
void *ref_;
};
Are there other "iterator wrappers" which I can use to define a pure virtual method in Base which takes all sorts of iterators and also acts like perfectly forwarding function template such that clients can pass iterators and move iterators?
No. Either you can have a virtual function, or you can have perfect forwarding, you can't have both.
What you can have is a type-erasing range, such as boost::any_range.
class Base {
public:
virtual void insert(boost::any_range<Class, std::input_iterator_tag> range) = 0;
};
To complement the other answer, here's something to get you up and running on implementing a polymorphic iterator if that's the desired solution. Rather than a forward iterator, I modelled an input iterator since that's all you need when taking a pair as a range to insert. The full sample can be found here.
Do note that this type fully models std::input_iterator, which means that it can be used anywhere any other input iterator can be used.
template<typename T>
class any_const_input_iterator_of {
// Store the actual iterator without its type.
std::any _erased;
// Store each operation we need from the actual iterator.
// Not ideal for space, but works as a starter example.
void(*_increment)(std::any& erased);
auto(*_deref)(const std::any& erased) -> const T&;
auto(*_equals)(const std::any& erased, const std::any& erased_other) -> bool;
public:
// Some required types to satisfy the iterator requirements.
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = const T;
// The constructor takes the real iterator.
// Since it knows the type, it can use the type in lambdas to fill in the operations.
// Normally, you wouldn't squish the important parts here.
template<std::input_iterator Iter>
requires std::equality_comparable<Iter> and
std::same_as<T, std::iter_value_t<Iter>> // We don't want a const T& return to be a temporary
any_const_input_iterator_of(Iter iter) :
_erased(iter),
_increment([](std::any& erased) { ++std::any_cast<Iter&>(erased); }),
_deref([](const std::any& erased) -> const T& { return *std::any_cast<Iter>(erased); }),
_equals([](const std::any& erased, const std::any& erased_other) {
assert(erased.type() == erased_other.type() and "Erased iterator types differ. This is probably a bug.");
return std::any_cast<Iter>(erased) == std::any_cast<Iter>(erased_other);
}) {}
// Now that we have operations, we can use them to implement the iterator requirements.
auto operator++() -> any_const_input_iterator_of& {
_increment(_erased);
return *this;
}
auto operator++(int) -> any_const_input_iterator_of {
auto copy = *this;
++*this;
return copy;
}
auto operator*() const -> const T& {
return _deref(_erased);
}
auto operator->() const -> const T* {
return &**this;
}
friend auto operator==(const any_const_input_iterator_of& lhs, const any_const_input_iterator_of& rhs) -> bool {
return lhs._equals(lhs._erased, rhs._erased);
}
};
static_assert(std::input_iterator<any_const_input_iterator_of<int>>);
There are two interesting things you might be wondering about. First, what about comparing with a sentinel? Well, I'm not sure this is even possible. The type of the sentinel, which needs to be available inside the lambda when calling operator==, is known only inside this class's operator==. There's no way to have both the iterator type and the sentinel type both known in the same place. If you limit sentinels to a finite list of types (as I did by requiring it to be the same type as the iterator), then your options open up a bit more.
Second, what about iterators whose value type is convertible to this one instead of an exact match? What if I want to pass set<double>::iterators as any_const_input_iterator_of<int>? Well, the issue here is lifetime. If dereferencing produces a double& and _deref returns const int&, then you're creating a temporary int that goes out of scope when _deref is done. Of course you can choose to return by value here and make copies. The problem really comes when the types do match. In this case, references are fine, but returning by value denies that. This is one of those things you have to live with when deciding to erase type information.
I wrote this template class for pointers usage
(I need smart pointers, but I can't use boost or C++11):
template<class T>
class TreePointer{
public:
TreePointer(){
isRefOnly=false;
data=NULL;
};
TreePointer(T* data){
this->data=data;
this->isRefOnly=false;
}
TreePointer(const TreePointer& anotherPtr){
this->data=anotherPtr.data;
this->isRefOnly=true;
}
virtual ~TreePointer(){
if (!isRefOnly){
delete data;
}
}
T* operator->() const{
return data;
}
void operator=(const TreePointer &anotherPtr){
this->data=anotherPtr.data;
this->isRefOnly=true;
}
private:
T* data;
bool isRefOnly;
};
And I have big class with many methods, like this:
class WrittenBigClassWithManyMethods{
public:
WrittenBigClassWithManyMethods(int v){
this->v=v;
}
int sum(WrittenBigClassWithManyMethods* a){
return v+a->v;
}
int v;
};
This usage of my smart pointers work perfectly:
TreePointer<WrittenBigClassWithManyMethods> tp(new WrittenBigClassWithManyMethods(5));
WrittenBigClassWithManyMethods* simpleClass=new WrittenBigClassWithManyMethods(5);
cout << tp->sum(simpleClass);
But it usage isn't work:
TreePointer<WrittenBigClassWithManyMethods> tp2(new WrittenBigClassWithManyMethods(5));
cout << tp->sum(tp2);
How i can change my template for pointers to make invoking methrod sum of class WrittenBigClassWithManyMethods with parameter of type TreePointer, without any changes for class WrittenBigClassWithManyMethods and its any usages? If this is not possible, how I minimize the changes for class WrittenBigClassWithManyMethods and its usage?
Usually you'll want to overload the unary operator * (de-reference) too, returning a T&. Then you can have both a reference and the original pointer by taking the address of the result:
tp1->method_that_takes_ref(*tp2); // With operator*()
tp1->method_that_takes_ptr(&*tp2); // Works, but syntax might be a bit surprising
Another way to get at the pointer inside would be to call operator -> directly, but that would be a bit awkward. You are likely better off providing some kind of "get" method, like the one in unique_ptr, that simply returns the raw pointer:
tp1->method_that_takes_ptr(tp2.operator->()); // Works, but ugh
tp1->method_that_takes_ptr(tp2.get()); // Much clearer
Add a conversion operator to T*:
operator T*() {
return data;
}
Now the compiler will call it whenever it wants to convert a TreePointer<SomeClass> to a SomeClass*.
I'm currently working on some code using smart pointers in which it is necessary at a number of points to cast these pointers to their base types and pass them as const arguments to functions. Currently I'm using shared_ptr's and the standard pointer casting functions to achieve this, but this seems inefficient (as each cast costs at least one CAS) and also misleading (as we are not modelling a shared relationship, the parent is the sole owner of the object).
I therefore came up with the following but wanted to check it is indeed safe, or is there some edge case which will break it?
template <typename ToType, typename FromType>
class FTScopedCastWrapper {
public:
explicit FTScopedCastWrapper(std::unique_ptr<FromType>& p) : from_ptr_(&p) {
auto d = static_cast<ToType *>(p.release());
to_ptr_ = std::unique_ptr<ToType>(d);
}
~FTScopedCastWrapper() {
auto d = static_cast<FromType *>(to_ptr_.release());
(*from_ptr_) = std::unique_ptr<FromType>(d);
}
const std::unique_ptr<ToType>& operator()() {
return to_ptr_;
}
// Prevent allocation on the heap
void* operator new(size_t) = delete;
void* operator new(size_t, void*) = delete;
void* operator new[](size_t) = delete;
void* operator new[](size_t, void*) = delete;
private:
std::unique_ptr<FromType>* from_ptr_;
std::unique_ptr<ToType> to_ptr_;
};
template <typename ToType, typename FromType>
FTScopedCastWrapper<ToType, FromType> FTScopedCast(std::unique_ptr<FromType>& p) {
return FTScopedCastWrapper<ToType, FromType>(p);
}
The intended usage is then
void testMethod(const std::unique_ptr<Base>& ptr) {
// Do Stuff
}
auto ptr = std::make_unique<Derived>();
testMethod(FTScopedCast<Base>(ptr)());
The deleter is not carried across as doing so would prevent upcasting. It also doesn't make sense to do so as the deleter will never be invoked on the created smart pointer anyway.
Allocation on the heap is prevented as it could allow the wrapper to outlive the pointer it wraps, copying is prevented by the std::unique_ptr member and standard destruction order will ensure the raw pointer is returned to the original smart pointer before it is destroyed, even if it is declared in the same scope as the wrapper.
I'm aware this is not thread safe but I'd argue sharing a unique_ptr between threads is breaking its contract of a single owner.
If I understand you correctly, the intention is to "steal" the contents of a std::unique_ptr for the duration of the function call, and then return it to its original owner when the function call is complete.
But this just seems needlessly convoluted. For a start, as pointed out by #TheUndeadFish in the comments, you could just take a raw Base* as the function argument and call it with std::unique_ptr::get(). As long as the called function doesn't do something silly like call delete on the passed-in pointer or squirrel it away in a static variable for later use then this will work just fine.
Alternatively, if you find raw pointers completely distasteful, you could use a non-owning pointer wrapper, something like the following (untested, but you get the idea):
template <typename T>
class unowned_ptr {
public:
unowned_ptr() = default;
unowned_ptr(const unowned_ptr&) = default;
unowned_ptr& operator=(const unowned_ptr&) = default;
template <typename U>
unowned_ptr(const U* other) : ptr(other) {}
template <typename U>
unowned_ptr(const std::unique_ptr<U>& other) : ptr(other.get()) {}
T* operator->() { return ptr; }
const T* operator->() const { return ptr; }
private:
T* ptr = nullptr;
};
Something very similar to this, std::observer_ptr ("the world's dumbest smart pointer") was proposed for C++17, but I'm not sure of the status.
I am a bit embarrassed of asking such a simple question:
Is there any pointer class in cpp that initializes itself with nullptr but is 100% compatible to a basic c-stylish pointer?
to write:
extern "C" void someFunction(const Struct* i_s);
std::ptr<Struct> p;
// ...
p = new Struct;
// ...
someFunction(p);
Is there such a thing?
Or maybe in boost or Qt?
Edit: to make it clear: iam not searching for a smart pointer that takes ownership of the pointer and does ref counting.
You can use the following syntax
std::unique_ptr<Struct> up{};
(or std::shared_ptr). This way, the pointer is value-initialized, i.e. nullptr is being assigned to it.
See http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr for details about the default constructor.
If you looking for a "smart" pointer that just initialized by default with nullptr, then you can write a wrapper. A very basic version below:
#include <iostream>
template <typename T>
struct safe_ptr
{
T* _ptr;
explicit safe_ptr(T* ptr = nullptr):_ptr{ptr}{}
operator T*() const {return _ptr;}
safe_ptr& operator=(T* rhs)
{
_ptr = rhs;
return *this;
}
};
void test(int* p){}
int main()
{
safe_ptr<int> s;
if(s==nullptr)
std::cout << "Yes, we are safe!" << std::endl;
// test that it "decays"
test(s);
s = new int[10]; // can assign
delete[] s; // can delete
}
There is no such thing in C++ since all of the special pointer classes implement some form of ownership other than "maintained by someone else". You could technically use shared_ptr with an empty deleter but that adds reference counting you don't actually need.
The correct C++ solution is to just always add = 0; or = nullptr; to your raw pointer declarations that aren't initialized at declaration.
All that said, this question is tagged just as C++ so the idiomatic answer is to not use raw pointers in your code (except for non-owning cases obviously).
100% compatible to a basic c-stylish pointer
std::unique_ptr and std::shared_ptr do not have automatic conversions to a raw pointer, and that's a good thing as it would inevitably lead to horrible bugs. They take ownership, and in your comments you explicitly say:
the pointer should not take ownership of the given Pointer.
If you insist, you can define a "smart" pointer class yourself:
template <class T>
class RawPointer final
{
private:
T* raw_ptr;
public:
RawPointer(T* raw_tr) : raw_ptr(raw_ptr) {}
RawPointer() : raw_ptr(nullptr) {}
operator T*() const { return raw_ptr; }
};
struct Struct
{
};
void someFunction(const Struct* i_s);
int main()
{
RawPointer<Struct> p;
someFunction(p);
}
Is this a good idea? Probably not. You should just get into the habit of initializing your raw pointers:
Struct* p = nullptr;
On the other hand, people are thinking about a very similar addition to the standard library in the future. You may find A Proposal for the World’s Dumbest Smart Pointer an interesting read.
If this is really the behavior that you want, it would be trivial to implement it yourself in a template. Here's one such implementation:
template<class T>
class ptr_t{
T* ptr;
public:
ptr_t() : ptr(nullptr){ }
ptr_t(const ptr_t& other) : ptr(other.ptr){ }
ptr_t(T* other) : ptr(other){ }
T& operator*(){
return *ptr;
}
T* operator->(){
return ptr;
}
template<class U>
operator U(){
return (U)ptr;
}
}
However, the amount of convenience you will gain from such a device will be rather limited. You're probably much better off taking another approach.
I'd like a pointer wrapper class that acts just like a raw pointer but also saves a special integer along with the pointer (Type's index in the array it came from)
I managed to have it behave mostly like a pointer. I am aware that the pointer comparison solution might not be optimal but that's not my main problem.
I want the wrapper to be constructed with 2 parameters(pointer,indexToArr), unless the pointer is NULL - then I don't care about indexToArr.
The problem I'm trying to solve is how to allow returning NULL just like a normal pointer allows.
current solution uses an ASSERT. But I want something that works in compile-time. something in the spirit of a specialized template method - allowing only NULL as its argument.
Current version:
class PtrWrapper
{
public:
PtrWrapper(Type* ptr, int indToArr)
: m_ptr(ptr), m_indexToArr(indToArr){}
//allow returning NULL, only NULL
PtrWrapper(Type* ptr) : m_ptr(NULL), m_indexToArr(-1) {ASSERT(ptr == NULL);}
Type* operator->() const {return m_ptr;}
Type& operator*() const {return *m_ptr;}
int IndexToArr() const {return m_indexToArr;}
//for pointer comparison
operator Type*() const {return m_ptr;}
private:
Type* m_ptr;
int m_indexToArr;
};
Any ideas, suggestions?
Thanks,
Leo
template<typename Type>
class PtrWrapper
{
typedef struct { } NotType;
public:
Ptr() { }
Ptr(const NotType* nullPtr) { }
Ptr(Type* p, int index) { }
};
You can exploit the fact that literal NULL / 0 can be auto-cast to any pointer type. Create a type that is NOT T, and a constructor which takes a single pointer to that type which nobody will ever use. Now you can handle PtrWrapper<T> x(NULL); explicitly.
Of course as others have said, this is only going to work if NULL is known at compile-time.
Simply make a default constructor with no arguments that initializes your pointer to NULL, but make sure to have some checks in your operator* and operator-> for a NULL pointer.
Do the following:
PtrWrapper(Type* ptr) : m_ptr(ptr), m_indexToArr(0) {ASSERT(ptr != NULL);}
PtrWrapper() : m_ptr(NULL), m_indexToArr(-1) {ASSERT(ptr == NULL);}