I'm trying to create a Read Only shared_ptr, shared between multiple instances. None of the instances should be able to modify the content of the pointer's object. But the instances should be able to copy it for an unknown period.
a const std::shared_ptr<T> cannot easily get stored in a attribute reference, as it has to be defined by the constructor. (and a const reference is, by definition, constant)
i did a wrapper class
template<class T>
class const_shared_ptr
{
public:
const_shared_ptr(std::shared_ptr<T> ptr)
{
m_ptr = ptr;
}
const T* get() const
{
return m_ptr.get();
}
private:
std::shared_ptr<T> m_ptr;
}
is this code clean ? or is there a more simpler way of doing ? this looks like a pretty easy problem but i can't figure any solution.
You can initialize a shared pointer to a const object from a shared pointer to a non-const object.
#include <memory>
void foo ()
{
auto v = std::make_shared <int> (10);
std::shared_ptr <int const> x = v;
// *x = 10; ERROR
}
Related
I am trying to replace raw pointers with smart pointers.
class MyObj {
public:
MyObj() {
rawContainer = new BigObj();
}
const BigObj* GetRawObj() {
return rawContainer;
}
private:
BigObj* rawContainer;
};
When I call
auto rawObj = myObj.GetRawObj() I avoid copying BigObj and can only call the functions marked const, so I can't modify it's content.
class MyObj {
public:
MyObj() {
std::unique_ptr<BigObj> ptr(new BigObj());
container = std::move(ptr);
}
const std::unique_ptr<BigObj>& GetObj() {
return container;
}
private:
std::unique_ptr<BigObj> container;
};
This time, with auto smartObj = myObj.GetObj(); I can access non-const methods of smartObj.
I understand the definition const std::unique_ptr<BigObj>& GetObj() is making the reference constant, and not the underlying object, but changing it to const std::unique_ptr<const BigObj>& GetObj() creates a compiler error.
Is there a sensible way to do this? I've seen suggestion of just returning a raw pointer from the smart pointer and using it like in the first example. The actual object in MyObj can't be const since it can actually be modified by some methods.
It is perfectly valid to declare const std::unique_ptr<const BigObj>& GetObj().
The problem must be somewhere else.
#include <memory>
class BigObj
{
};
class MyObj
{
public:
MyObj(): container(std::make_unique<BigObj>()) {}
auto GetObj() -> const std::unique_ptr<const BigObj>&
{
return reinterpret_cast<const std::unique_ptr<const BigObj>&>(container);
}
private:
std::unique_ptr<BigObj> container;
};
auto main()->int
{
MyObj obj;
obj.GetObj();
}
https://onlinegdb.com/xzHzI4GgM
Like the commenters above is suggesting. Just return a raw pointer. There is no reason to return a reference to the unique_ptr below.
#include <memory>
struct BigObj {
int bigData = 1000;
};
class MyObj {
public:
const BigObj& getObj() const {
return *container;
}
// Alternative if you want a pointer instead of a reference
// (you probably don't if you know that the pointer is non null)
//const BigObj* getObj2() const {
// return container.get();
//}
private:
std::unique_ptr<BigObj> container = std::make_unique<BigObj>();
};
int main() {
auto myObj = MyObj{};
auto &ref = myObj.getObj();
}
Note: There is syntax if you want to be able to move a ptr out of the object, but I guess that that is not a part of the question.
I work with unique_ptr on derived structs, and I return references to maintain ownership and keep minimal overhead.
Basically, I want a get function to turn unique_ptr<Base> into unique_ptr<Derived>&.
I can't use dynamic_pointer_cast as it copies and fails :
no matching function for call to 'dynamic_pointer_cast<Derived>(std::unique_ptr<Base>&)'
I can't use std::move or release from obj, as it is the source of truth of the program.
Do you guys see any alternative?
The shared_ptr version works OK btw, is it the only path?
Thanks in advance for your input.
JD
#include <memory>
struct Base {
};
struct Derived : public Base {
float position;
Derived(float position_) : position(position_) {}
};
//SOURCE OF TRUTH
std::unique_ptr<Base> obj;
//retreive from obj
template<typename T>
std::unique_ptr<T>& get() {
std::unique_ptr<Base> &p = obj;
return std::dynamic_pointer_cast<T>(p); //<-- pb: fails because it copies...
}
int main() {
//storing
obj = std::make_unique<Derived>(10.0f);
// ...
//retrieving
std::unique_ptr<Derived>& p = get<Derived>();
return 0;
}
You can still just do a regular dynamic_cast with the raw pointer, ie.:
template<typename T>
T* get() {
std::unique_ptr<Base> &p = obj;
return dynamic_cast<T*>(p.get());
}
Semanticly that is ok as raw pointer is taken to mean non-owning.
get should return a non-owning pointer, because it shouldn't be changing the ownership.
template<typename T>
T * get() {
return std::dynamic_cast<T *>(obj.get());
}
Short answer: Don't!
Long Answer: A unique pointer deals with ownership and a reference has no ownership semantic. You may return a (const) reference instead. If you need to share ownership use std::shared_pointer.
I have a class that can take both a non-const pointer or a const pointer as arguments to its overloaded constructors. In my particular case, I need to instantiate an object of this class from both const and non-const methods of class T, but it fails from const methods, as it can't assign the const pointer to foo .
myClass() {
public:
myClass(T* v);
myClass(const T* v);
// ...
T* foo;
// ...
}
Is it possible to assign the argument in both constructors to foo? If so, what would be the correct syntax?
EDIT:
In a more specific case, I have a class myClass that wraps around std::vector and allows to me to directly access subsets of a vector through a nested class mySubset:
template<typename _type>
myClass() {
std::vector<_type> data;
public:
class mySubset(){
myClass<type>* foo;
public:
mySubset(myClass<_type>* _in) { foo = _in; };
mySubset(const myClass<_type>* _in) { foo = _in; /* error */ };
// ...
}
// ...
myClass();
// ...
void mySubset method() { return mySubset(this); };;
void mySubset const_method const() { return mySubset(this); /* error */ };
// ...
}
The code within is irrelevant -basically mySubset allows to both read and write to specific vector positions. While I'm able to achieve what I want with separate const and non-const nested classes, I was looking for a way to do this with a single return type.
I think you'll have to reconsider your design since you can't initialize a T* with a const T* lvalue, without const_cast which should be avoided unless you're really really sure, (since it invokes an undefined behavior if you try to modify a const pointer after casting away its constness)
Instead, you could use template type deduction for const and non const
template <typename T>
class myClass {
public:
//myClass(T* v):foo(v) { }
myClass( T* v):foo(v)
{
}
// ...
T* foo;
// ...
};
Then,
int a =42;
const int* p1 = &a;
int *p2 = &a;
myClass X1(p1); //C++17 auto type deduction or use myClass<const int> X1(p1)
myClass X2(p2);
You could using const_cast in your const T* constructor, but typically you shouldn't.
const T* means "point to a constant value T", and you store a "pointer to a T". If you do a const cast, you could end up modifying a value which shouldn't be modified. If you aren't going to modify foo, just declare it const T* and just use the single const T* constructor.
I'd check to see if this is a design issue. A lot of the times these scenarios appear:
(1) Where you're storing a pointer to something as non-const when it should be const. Typically this is because you're accessing values in another object and you should be passing the object as a (possibly const) reference at each use site rather than storing a pointer to it.
(2) When you really want to store a copy of an object, in which case you just keep a regular T and pass it in as const T& in the constructor.
(3) You're dealing with raw C-style strings and want to copy the contents into your own buffer.
If you don't want to use parameterized-type (template) class as #P0W's answer, it is not possible you can use only one pointer to accept all constant and non-constant pointer type. You need another constant pointer type to accept only const <your another class> * in your wrapper class.
Below code works after you have two separate pointer types in wrapper class which you may not like.
#include <iostream>
using namespace std;
class SomeObject {
public:
SomeObject(){}
explicit SomeObject(int i):testVal(i){}
private:
int testVal;
};
class PtWrapper {
public:
PtWrapper(SomeObject *pso);
PtWrapper(const SomeObject *cpso);
private:
SomeObject *pSO;
const SomeObject *cpSO;
};
int main(int argc, char *argv[]) {
SomeObject so(133);
SomeObject *pso = &so;
const SomeObject cso(166);
const SomeObject *cpso = &cso;
PtWrapper pw1(pso);
PtWrapper pw2(cpso);
return 0;
}
PtWrapper::PtWrapper(SomeObject *pso) :pSO(pso){
}
PtWrapper::PtWrapper(const SomeObject *cpso):cpSO(cpso){}
Say I have a simple class like this
class Foo
{
public:
void foo()const
{
str[5] = 'x';
obj->changeTheWorld();
x = 4;
y.get() = 5;
obj2->changeTheWorld();
}
private:
char *str; //some referenced data, not owned by Foo
ComplexObj *obj; //some referenced data, not owned by Foo
int &x; //references as well
//wrapped reference, but has a "T& get()const"
std::reference_wrapper<int> y;
//an occasionally useful pointer wrapper for complex memory cases
//but has a "T* get()const"
std::shared_ptr<ComplexObj> obj2;
};
This is valid because in the const method, its just the pointer itself that becomes const, not the data it points to. However in many cases that is not what I desired and I want a compile error if a const method tries to change these members contents (either directly or by calling a non-const method on that member).
Is there a standard solution to this?
I think some kind of wrapper class should be able to achieve this, and should also be something the compiler optimises out, although haven't sat down to try and design such a thing to cover all cases giving say a strong_const<char*> str and strong_const<int&> (also not sure on a good name...).
Well, neither std::reference_wrapper nor std::shared_ptr do not provide const propagation, so they are not more "const-strict" than regular pointer.
I'd recommend to make your own const propagation class (I am not sure - maybe something similar is already provided by boost - please let me know in comments)
My proposition is this class:
#include <memory> // for pointer_traits
template <typename Pointer>
class ConstPropagatePointer
{
public:
using element_type = typename std::pointer_traits<Pointer>::element_type;
using pointer = typename std::pointer_traits<Pointer>::pointer;
using const_pointer = element_type const * const;
using reference = element_type&;
using const_reference = element_type const&;
ConstPropagatePointer(Pointer ptr) : ptr(ptr) {}
pointer operator -> ()
{
return &(*ptr);
}
const_pointer operator -> () const
{
return &(*ptr);
}
reference operator * ()
{
return *ptr;
}
const_reference operator * () const
{
return *ptr;
}
private:
Pointer ptr;
};
So that will work for you:
class Foo
{
public:
private:
ConstPropagatedPointer<char*> str;
ConstPropagatedPointer<ComplexObj*> obj;
ConstPropagatedPointer<std::shared_ptr<ComplexObj>> obj2;
};
I have a function that given a path name, does a look up and returns a pointer to the associated value. Sometimes the value lives in a static cache, sometimes it gets calculated and created on the fly.
So, sometimes the caller takes ownership and needs to delete the object after reading it, and sometimes not. I'm wondering, is there something I can wrap this pointer with so that it will automatically be freed as necessary by the caller?
I was thinking I might be able to use a unique_ptr, but isn't the deleter part of the type, so how could I return the same type that sometimes does and sometimes doesn't actually delete.
So indeed, one solution could be returning a normal std::shared_ptr for the value created inside the function, and another one with an empty deleter for the value that lives in the map.
Live example of this solution
You can see how both use cases don't require any actions from the calling code and are completely transparent.
You can use std::unique_ptr with a deleter that knows whether to free or not. While the deleter type is part of the unique_ptr type, different unique_ptr instances can have different deleter instances:
template <class T>
class delete_if_not_cached {
bool cached;
public:
delete_if_not_cached(bool c = false) : cached(c) {}
void operator()(T *obj) { if (!cached) delete obj; }
}
and you have your function return a std::unique_ptr<T, delete_if_not_cached<T>>. If you're returning a pointer into the cache, you create that pointer as:
return std::unique_ptr<T, delete_if_not_cached<T>>(raw_pointer, delete_if_not_cached<T>(true));
to return a non-cached object, use
return std::unique_ptr<T, delete_if_not_cached<T>>(new T(...))
One potential pitfall is that if you ever remove things from the cache, that might leave dangling unique_ptrs that you have previously returned. If that's an issue, it probably makes more sense to use shared_ptrs both to return and in the cache itself.
You could use a std::shared_ptr but that does not really describe your ownership model. Have you considered rolling your own wrapper that contains a std::unique_ptr and a raw pointer and uses the correct one depending on the circumstances? Something like:
#include <cassert>
#include <memory>
class MyClass { };
class Wrapper {
const MyClass* cached_;
std::unique_ptr<MyClass> owned_;
public:
Wrapper() : cached_(nullptr) {}
void setCached(const MyClass* cached) {cached_ = cached;}
void setOwned(std::unique_ptr<MyClass> owned) { owned_ = std::move(owned); }
const MyClass* get() const {return cached_ ? cached_ : owned_.get();}
};
Wrapper getWrapper(int i) {
static MyClass first;
static MyClass second;
Wrapper wrapper;
if (i == 0)
wrapper.setCached(&first);
else if (i == 1)
wrapper.setCached(&second);
else
wrapper.setOwned(std::unique_ptr<MyClass>(new MyClass()));
return wrapper;
}
int main() {
for (int i = 0; i != 4; ++i) {
Wrapper wrapper = getWrapper(i);
assert(wrapper.get() != nullptr);
}
}
The wrapper can either forward calls to the real class or provide access to a raw pointer to the real class.
Or the wrapper could work polymorphically, with an interface and two implementations. One with a raw pointer and one with a unique pointer:
#include <cassert>
#include <memory>
class MyClass {};
class Wrapper {
public:
virtual ~Wrapper() = 0;
virtual const MyClass* get() const = 0;
};
Wrapper::~Wrapper() {}
class OwnerWrapper : public Wrapper {
std::unique_ptr<MyClass> owned_;
public:
OwnerWrapper(std::unique_ptr<MyClass> in) : owned_(std::move(in)) {}
virtual const MyClass* get() const { return owned_.get(); }
};
class PtrWrapper : public Wrapper {
const MyClass* ptr_;
public:
PtrWrapper(const MyClass* ptr) : ptr_(ptr) {}
virtual const MyClass* get() const { return ptr_; }
};
std::unique_ptr<Wrapper> getWrapper(int i) {
static MyClass first;
static MyClass second;
if (i == 0)
return std::unique_ptr<Wrapper>(new PtrWrapper(&first));
else if (i == 1)
return std::unique_ptr<Wrapper>(new PtrWrapper(&second));
else {
std::unique_ptr<MyClass> myclass(new MyClass());
return std::unique_ptr<Wrapper>(new OwnerWrapper(std::move(myclass)));
}
}
int main() {
for (int i = 0; i != 4; ++i) {
auto wrapper = getWrapper(i);
assert(wrapper->get() != nullptr);
}
}