Cannot convert from std::shared_ptr<_Ty> to std::shared_ptr<_Ty> - c++

I am getting the following error:
error C2440: 'static_cast' : cannot convert from 'std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty> stack\genericstack.h 36 1 Stack
GenericStack.h
#ifndef _GENERIC_STACK_TROFIMOV_H_
#define _GENERIC_STACK_TROFIMOV_H_
#include <memory>
class GenericStack {
struct StackNode {
std::shared_ptr<void> _data;
StackNode* _next;
StackNode(const std::shared_ptr<void>& data, StackNode* next)
: _data(data), _next(next) {
}
};
StackNode* _top;
GenericStack(const GenericStack&);
GenericStack& operator=(const GenericStack&);
protected:
GenericStack();
~GenericStack();
void push(const std::shared_ptr<void>&);
void pop();
std::shared_ptr<void>& top();
bool isEmpty() const;
};
template <class T>
class TStack: private GenericStack {
public:
void push(const std::shared_ptr<T>& p) { GenericStack::push(p); }
void pop() { GenericStack::pop(); }
std::shared_ptr<T> top() { return static_cast<std::shared_ptr<T>>(GenericStack::top()); }
bool empty() const { return GenericStack::isEmpty(); }
};
#endif
GenerickStack.cpp
#include "GenericStack.h"
GenericStack::GenericStack()
:_top(0) {
};
GenericStack::~GenericStack() {
while(!isEmpty()) {
pop();
}
};
void GenericStack::push(const std::shared_ptr<void>& element) {
_top = new StackNode(element, _top);
}
std::shared_ptr<void>& GenericStack::top() {
return _top->_data;
}
void GenericStack::pop() {
StackNode* t = _top->_next;
delete _top;
_top = t;
}
bool GenericStack::isEmpty() const {
return !_top;
}
Main.cpp
#include <iostream>
#include "GenericStack.h"
int main() {
TStack<int> gs;
std::shared_ptr<int> sh(new int(7));
gs.push(sh);
std::cout << *gs.top() << std::endl;
return 0;
}
Why am I getting the error?
I would expect the cast to happen successfully, since with raw pointers I always can case from void* to the real type pointer.
What I want to do here is to create a stack template. But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
Thank you.

You get that error because static_cast requires the types from and to to be convertible. For shared_ptr that will hold only if c'tor overload 9 would participate in overload resolution. But it doesn't, because void* is not implicitly convertible to other object pointer types in C++, it needs an explicit static_cast.
If you want to convert shared pointers based on static_casting the managed pointer types, you need to use std::static_pointer_cast, that is what it's for.
So after plugging that fix
std::shared_ptr<T> top() { return std::static_pointer_cast<T>(GenericStack::top()); }
Your thin template wrapper will build fine.

Take a look at the list of constructors for shared_ptr. You are trying to use overload 9, more specifically the template overload with Y = void and T = int. However, this template overload doesn't participate in overload resolution, because void* is not implicitly convertible to int*. In other words, you cannot convert, even explicitly, shared_ptr<void> to shared_ptr<T> if you cannot implicitly convert void* to T*.
Why not use a template in the first place (move GenericStack functionality into TStack), instead of trying to deal with void*?
But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
By "swell", I assume you mean the template solution would generate too many instances? Do you have any reason to believe that it would indeed be too many?

Related

How to provide const version of operator -> for a handle class

I am trying to overload my operator-> for a handle class to return const and non const pointer, pointing towards a base class.
Looking at the code i posted, in the trial function, if i add in the const keyword, the error message will be
||=== Build: Debug in Const trial (compiler: GNU GCC Compiler) ===|
C:\Const trial\main.cpp
||In function 'bool trial(Cards_pointer)':|
C:\Const trial\main.cpp|50|error: passing 'const Cards_pointer' as 'this' argument of 'Cards*& Cards_pointer::operator->()' discards qualifiers [-fpermissive]|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
My question is whether it is possible to do so, if yes, may i know what is the correct implementation?
#include <iostream>
#include<vector>
#include<stdexcept>
#include<algorithm>
using namespace std;
class Cards
{
private:
int x;
public:
Cards():x(3) {}
int rx()const
{
return x;
}
};
class Cards_pointer
{
private:
Cards* cp;
size_t* refptr;
public:
//default constructor
Cards_pointer():cp(0),refptr(new size_t(1)) {}
Cards_pointer(Cards*t):cp(t),refptr(new size_t(1)) {}
//copy constructor
Cards_pointer (const Cards_pointer&s):cp(s.cp),refptr(s.refptr)
{
refptr=s.refptr;
cp=s.cp;
//++*refptr;
*refptr=*refptr+1;
}
Cards*&operator->()
{
if(cp)
return cp;
else throw std::runtime_error("uninitialized Cards");
}
};
bool trial(const Cards_pointer x)
{
if(x->rx()==3)
return true;
return false;
}
int main()
{
Cards_pointer x=new Cards();
bool cond=trial(x);
}
Just return a pointer to const and provide a const qualified overload
class Something {
public:
void bar() {}
void foo() const {}
};
class Wrapper {
public:
Something* operator->() {
return &this->something;
}
const Something* operator->() const {
return &this->something;
}
private:
Something something;
};
int main() {
const auto c_wrapper = Wrapper{};
c_wrapper->foo();
// The below is an error
// c_wrapper->bar();
auto m_wrapper = Wrapper{};
m_wrapper->bar();
}
If you are worried about duplicated code in the const and non const overloads see Const function calling non const or vice versa (to avoid duplication)?
If you overload your operator->, the behaviour will not mimick that of built-in pointers (and will not make much sense at all).
Built-in pointers come in two flavours: pointers and pointers-to-const. (We ignore volatile here). These flavours are different types. Pointers themselves being const have nothing to do with constness of what they point to.
In order to imitate this behaviour, you need two flavours of Cards_pointer, one with operator-> that returns a normal pointer, and one with operator-> that returns a pointer-to-const.
class Cards_pointer_base { ... };
class Cards_pointer: private Cards_pointer_base {
public:
// usual constructors/assignment operators
using ...; // necessary members from the base
Cards* operator->() { ... }
};
class Cards_const_pointer: private Cards_pointer_base {
public:
// usual constructors/assignment operators
using ...; // necessary members from the base
const Cards* operator->() { ... }
// conversions from pointer to non-const
Cards_const_pointer(const Cards_pointer& from) { ... }
Cards_const_pointer& operator=(const Cards_pointer& from) { ... }
};
Standard smart pointers are class templates, so one can just write shared_ptr<Cards> and shared_ptr<const Cards>.

Debugging crash in small object optimization for type erasure

I'm implementing a class that performs type erasure for small objects and have encountered a segmentation fault which I do not understand.
The following program:
#include <iostream>
#include <type_traits>
struct small_object
{
public:
template<class T>
small_object(const T& value)
{
new(&storage_) concrete<T>(value);
}
~small_object()
{
get_abstract().~abstract();
}
void print() const
{
// XXX crash here
get_abstract().print();
}
private:
struct abstract
{
virtual ~abstract(){}
virtual void print() const = 0;
};
template<class T>
struct concrete
{
concrete(const T& value) : value_(value) {}
void print() const
{
std::cout << value_ << std::endl;
}
T value_;
};
abstract& get_abstract()
{
return *reinterpret_cast<abstract*>(&storage_);
}
const abstract& get_abstract() const
{
return *reinterpret_cast<const abstract*>(&storage_);
}
typename std::aligned_storage<4 * sizeof(void*)> storage_;
};
int main()
{
small_object object(13);
// XXX i expect this line to print '13' to the terminal but it crashes
object.print();
return 0;
}
Crashes at the lines indicated by XXX.
I believe the issue is that the virtual call to .print() is not being dynamically dispatched correctly, but I don't understand why.
Can anyone tell what am I missing?
You didn't derive concrete<T> from abstract, so no vtable is being created when you construct the object using placement new. Therefore, when you try to invoke the virtual function, it will fail; concrete<T> and abstract are actually completely unrelated types in this example.
I would recommend using the override keyword if you're using C++11 or newer to allow the compiler to generate an error in cases like this.
std::aligned_storage<4 * sizeof(void*)> storage_;
This creates storage of one byte.
The template argument does not set the size of the declared object, but rather the size of an object that can be allocated in a suitably-sized array of this type. Hence, you need
std::aligned_storage<4 * sizeof(void*)> storage_[4 * sizeof(void*)];
GCC 6.2.0 warns you about this:
warning: placement new constructing an object of type ‘small_object::concrete<int>’ and size ‘16’ in a region of type ‘std::aligned_storage<32ul>’ and size ‘1’ [-Wplacement-new=]
(You still need to derive concrete from abstract).

Make a safe Reader/Writer vector

Inspired by this code, I am trying to implement a Reader/Writer vector that can safely call push_back() concurrently by threads.
Once this class is in place, I might then create method erase() by calling std::swap(), which swaps the target item and the last item and then erase the last item in the collection. In this way, I assume that the performance should be fair because deleting an item in the middle of collection does not invoke moving all items following the target item in the collection.
Unfortunately, the following code:
#include <vector>
#include <boost/thread/shared_mutex.hpp> //shared_mutex
#include <memory> //shared_ptr
#include <utility> //swap()
template <class T>
class readers_writer_vector
{
std::shared_ptr<boost::shared_mutex> pm;
std::vector<T> data;
public:
readers_writer_vector() :
pm(new std::shared_ptr<boost::shared_mutex>){}
void push_back(const T& item){
boost::unique_lock<boost::shared_mutex> lock(*pm); //wrong design
data.push_back(item);
}
};
int main()
{
readers_writer_vector<int> db;
db.push_back(1);
return 0;
}
yields the following compilation errors:
/usr/include/c++/4.9/bits/shared_ptr_base.h:871:39: error: cannot convert ‘std::shared_ptr<boost::shared_mutex>*’ to ‘boost::shared_mutex*’ in initialization
: _M_ptr(__p), _M_refcount(__p)
// g++ -std=c++11 -Iboost -lboost t.cpp
How do I fix it? Please!
EDIT:
The implementation task is far more complicated than I thought. It didn't take too long before I encountered the problem #Danh had warned. Now I get these errors:
t.cpp:28:8: note: ‘i::i(const i&)’ is implicitly deleted because the default definition would be ill-formed:
struct i {
^
t.cpp:28:8: error: use of deleted function ‘readers_writer_vector<T>::readers_writer_vector(const readers_writer_vector<T>&) [with T = z]’
t.cpp:13:2: note: declared here
readers_writer_vector(readers_writer_vector const&) = delete;
with this version:
template <class T>
class readers_writer_vector
{
booster::shared_mutex m;
std::vector<T> data;
public:
readers_writer_vector() = default;
readers_writer_vector(readers_writer_vector const&) = delete;
void push_back(const T& item){
booster::unique_lock<booster::shared_mutex> lock(m);
data.push_back(item);
}
typename std::vector<T>::reference back(){
return data.back();
}
};
struct z {
int zipcode;
std::string address;
};
struct i {
int id;
readers_writer_vector<z> zipcodes;
};
int main()
{
readers_writer_vector<i> db;
db.push_back(i());
auto &ii=db.back();
ii.id=1;
ii.zipcodes.push_back(z());
auto &zz=ii.zipcodes.back();
zz.zipcode=11;
zz.address="aa";
return 0;
}
In addition to fixing the existing errors, I will have to implement iterators for readers_writer_vector to make this class useful.
I am pondering whether or not I should continue...
Because pm is std::shared_ptr<boost::shared_mutex> not std::shared_ptr<boost::shared_mutex>*. You can use this:
readers_writer_vector() :
pm(std::make_shared<boost::shared_mutex>()){}
Anyway, why do you need pointer/smart pointer? This is better fit:
template <class T>
class readers_writer_vector
{
boost::shared_mutex pm;
std::vector<T> data;
public:
void push_back(const T& item){
boost::unique_lock<boost::shared_mutex> lock(pm);
data.push_back(item);
}
};
You're initialising pm with the wrong type; you effectively have
std::shared_ptr<> pm = new std::shared_ptr<>;
You can't assign a shared pointer from a pointer to shared pointer.
Replace the initialiser with
pm(new boost::shared_mutex)
or make the mutex a member directly, rather than using shared pointer.

C++ Reference Handle

concerning code from Accelerated C++:
template <class T> class Ref_handle {
public:
Ref_handle(): refptr(new size_t(1)), p(0) { }
Ref_handle(T* t): refptr(new size_t(1)), p(t) { }
Ref_handle(const Ref_handle& h): refptr(h.refptr), p(h.p)
{
++*refptr; //???
}
~Ref_handle();
private:
T* p;
size_t* refptr;
};
I understand the principle of handle, but I don't understand why compiler allows this kind op copy constructor. It copies pointers, but since it's pointing to a same size_t object, it's actually changing its value, although we "promised" with const that we won't change it.

Building boost::options from a string/boost::any map

I have a map which represents a configuration. It's a map of std::string and boost::any.
This map is initialized at the start and I'd like the user to be able to override these options on the command line.
What I'd love to do is build the program options from this map using the options_description::add_option() method. However, it takes a template argument po::value<> whereas all I have is boost::any.
So far, I just have the shell of the code. m_Config represents my configuration class, and getTuples() returns a std::map<std::string, Tuple>. TuplePair is a typedef of std::pair<std::string, Tuple> and the Tuple contains the boost::any I am interested in.
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
// what goes here? :)
// desc.add_options() ( _pair.first, po::value<???>, "");
});
Is there a way to build it this way, or do I need to resort to doing it myself?
Thanks in advance!
boost::any is not applicable to your problem. It performs the most basic form of type erasure: storage and (type-safe) retrieval, and that's it. As you've seen, no other operations can be performed. As jhasse points out, you could just test every type you want to support, but this is a maintenance nightmare.
Better would be to expand upon the idea boost::any uses. Unfortunately this requires a bit of boiler-plate code. If you'd like to try it, there's a new Boost library being discussed right now on the mailing list (titled "[boost] RFC: type erasure") that is essentially a generalized type erasure utility: you define the operations you'd like your erased type to support, and it generates the proper utility type. (It can simulate boost::any, for example, by requiring the erased type be copy-constructible and type-safe, and can simulate boost::function<> by additionally requiring the type be callable.)
Aside from that, though, your best option is probably to write such a type yourself. I'll do it for you:
#include <boost/program_options.hpp>
#include <typeinfo>
#include <stdexcept>
namespace po = boost::program_options;
class any_option
{
public:
any_option() :
mContent(0) // no content
{}
template <typename T>
any_option(const T& value) :
mContent(new holder<T>(value))
{
// above is where the erasure happens,
// holder<T> inherits from our non-template
// base class, which will make virtual calls
// to the actual implementation; see below
}
any_option(const any_option& other) :
mContent(other.empty() ? 0 : other.mContent->clone())
{
// note we need an explicit clone method to copy,
// since with an erased type it's impossible
}
any_option& operator=(any_option other)
{
// copy-and-swap idiom is short and sweet
swap(*this, other);
return *this;
}
~any_option()
{
// delete our content when we're done
delete mContent;
}
bool empty() const
{
return !mContent;
}
friend void swap(any_option& first, any_option& second)
{
std::swap(first.mContent, second.mContent);
}
// now we define the interface we'd like to support through erasure:
// getting the data out if we know the type will be useful,
// just like boost::any. (defined as friend free-function)
template <typename T>
friend T* any_option_cast(any_option*);
// and the ability to query the type
const std::type_info& type() const
{
return mContent->type(); // call actual function
}
// we also want to be able to call options_description::add_option(),
// so we add a function that will do so (through a virtual call)
void add_option(po::options_description desc, const char* name)
{
mContent->add_option(desc, name); // call actual function
}
private:
// done with the interface, now we define the non-template base class,
// which has virtual functions where we need type-erased functionality
class placeholder
{
public:
virtual ~placeholder()
{
// allow deletion through base with virtual destructor
}
// the interface needed to support any_option operations:
// need to be able to clone the stored value
virtual placeholder* clone() const = 0;
// need to be able to test the stored type, for safe casts
virtual const std::type_info& type() const = 0;
// and need to be able to perform add_option with type info
virtual void add_option(po::options_description desc,
const char* name) = 0;
};
// and the template derived class, which will support the interface
template <typename T>
class holder : public placeholder
{
public:
holder(const T& value) :
mValue(value)
{}
// implement the required interface:
placeholder* clone() const
{
return new holder<T>(mValue);
}
const std::type_info& type() const
{
return typeid(mValue);
}
void add_option(po::options_description desc, const char* name)
{
desc.add_options()(name, po::value<T>(), "");
}
// finally, we have a direct value accessor
T& value()
{
return mValue;
}
private:
T mValue;
// noncopyable, use cloning interface
holder(const holder&);
holder& operator=(const holder&);
};
// finally, we store a pointer to the base class
placeholder* mContent;
};
class bad_any_option_cast :
public std::bad_cast
{
public:
const char* what() const throw()
{
return "bad_any_option_cast: failed conversion";
}
};
template <typename T>
T* any_option_cast(any_option* anyOption)
{
typedef any_option::holder<T> holder;
return anyOption.type() == typeid(T) ?
&static_cast<holder*>(anyOption.mContent)->value() : 0;
}
template <typename T>
const T* any_option_cast(const any_option* anyOption)
{
// none of the operations in non-const any_option_cast
// are mutating, so this is safe and simple (constness
// is restored to the return value automatically)
return any_option_cast<T>(const_cast<any_option*>(anyOption));
}
template <typename T>
T& any_option_cast(any_option& anyOption)
{
T* result = any_option_cast(&anyOption);
if (!result)
throw bad_any_option_cast();
return *result;
}
template <typename T>
const T& any_option_cast(const any_option& anyOption)
{
return any_option_cast<T>(const_cast<any_option&>(anyOption));
}
// NOTE: My casting operator has slightly different use than
// that of boost::any. Namely, it automatically returns a reference
// to the stored value, so you don't need to (and cannot) specify it.
// If you liked the old way, feel free to peek into their source.
#include <boost/foreach.hpp>
#include <map>
int main()
{
// (it's a good exercise to step through this with
// a debugger to see how it all comes together)
typedef std::map<std::string, any_option> map_type;
typedef map_type::value_type pair_type;
map_type m;
m.insert(std::make_pair("int", any_option(5)));
m.insert(std::make_pair("double", any_option(3.14)));
po::options_description desc;
BOOST_FOREACH(pair_type& pair, m)
{
pair.second.add_option(desc, pair.first.c_str());
}
// etc.
}
Let me know if something is unclear. :)
template<class T>
bool any_is(const boost::any& a)
{
try
{
boost::any_cast<const T&>(a);
return true;
}
catch(boost::bad_any_cast&)
{
return false;
}
}
// ...
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
if(any_is<int>(_pair.first))
{
desc.add_options() { _pair.first, po::value<int>, ""};
}
else if(any_is<std::string>(_pair.first))
{
desc.add_options() { _pair.first, po::value<std::string>, ""};
}
else
{
// ...
}
});
// ...
If you have more than a handful of types consider using typelists.