Can smart pointers be implicitly used as pointers? - c++

Are smart pointers considered as pointers? And thus can they implicitly used as pointers?
Let's say I have the following class:
class MyClass {
//...
std::shared_ptr<AnotherClass> foo() { /*whatever*/ };
void bar(AnotherClass* a) { /*whatever too*/ };
//...
}
Then can I use MyClass the following way?
// m is an instance of MyClass
m.bar(m.foo());

No they can't be used interchangable. You would get a compiler error in your example. But you can always get the raw pointer by shared_ptr::get().

NO! It would be a terrible API. Yes, you could easily implement it within shared_ptr, but just because you could doesn't mean you should.
Why is it such a bad idea? The plain-pointer-based interface of bar doesn't retain an instance of the shared pointer. If bar happens to store the raw pointer somewhere and then exit, there's nothing that guarantees that the pointer it had stored won't become dangling in the future. The only way to guarantee that would be to retain an instance of the shared pointer, not the raw pointer (that's the whole point of shared_ptr!).
It gets worse: the following code is undefined behavior if foo() returns a pointer instance that had only one reference when foo() returned (e.g. if foo is a simple factory of new objects):
AnotherClass *ptr = m.foo().get();
// The shared_ptr instance returned by foo() is destroyed at this point
m.bar(ptr); // undefined behavior: ptr is likely a dangling pointer here
Here are the options; consider those listed earlier first before considering their successors.
If bar(AnotherClass *) is an external API, then you need to wrap it in a safe way, i.e. the code that would have called Original::bar should be calling MyWrapped::bar, and the wrapper should do whatever lifetime management is necessary. Suppose that there is startUsing(AnotherClass *) and finishUsing(AnotherClass *), and the code expects the pointer to remain valid between startUsing and finishUsing. Your wrapper would be:
class WithUsing {
std::unique_ptr<AnotherClass> owner; /* or shared_ptr if the ownership is shared */
std::shared_ptr<User> user;
public:
WithUsing(std::unique_ptr<AnotherClass> owner, std::Shared_ptr<User> user) :
owner(std::move(owner)), user(std::move(user)) {
user.startUsing(owner.get());
}
void bar() const {
user.bar(owner.get());
}
~WithUsing() {
user.finishUsing(owner.get());
}
};
You would then use WithUsing as a handle to the User object, and any uses would be done through that handle, ensuring the existence of the object.
If AnotherClass is copyable and is very cheap to copy (e.g. it consists of a pointer or two), then pass it by value:
void bar(AnotherClass)
If the implementation of bar doesn't need to change the value, it can be defined to take a const-value (the declaration can be without the const as it doesn't matter there):
void bar(const AnotherClass a) { ... }
If bar doesn't store a pointer, then don't pass it a pointer: pass a const reference by default, or a non-const reference if necessary.
void bar(const AnotherClass &a);
void bar_modifies(AnotherClass &a);
If it makes sense to invoke bar with "no object" (a.k.a. "null"), then:
If passing AnotherClass by value is OK, then use std::optional:
void bar(std::optional<AnotherClass> a);
Otherwise, if AnotherClass takes ownership, passing unique_ptr works fine since it can be null.
Otherwise, passing shared_ptr works fine since it can be null.
If foo() creates a new object (vs. returning an object that exists already), it should be returning unique_ptr anyway, not a shared_ptr. Factory functions should be returning unique pointers: that's idiomatic C++. Doing otherwise is confusing, since returning a shared_ptr is meant to express existing shared ownership.
std::unique_ptr<AnotherClass> foo();
If bar should take ownership of the value, then it should be accepting a unique pointer - that's the idiom for "I'm taking over managing the lifetime of that object":
void bar(std::unique_ptr<const AnotherClass> a);
void bar_modifies(std::unique_ptr<AnotherClass> a);
If bar should retain shared ownership, then it should be taking shared_ptr, and you will be immediately converting the unique_ptr returned from foo() to a shared one:
struct MyClass {
std::unique_ptr<AnotherClass> foo();
void bar(std::shared_ptr<const AnotherClass> a);
void bar_modifies(std::shared_ptr<AnotherClass> a);
};
void test() {
MyClass m;
std::shared_ptr<AnotherClass> p{foo()};
m.bar(p);
}
shared_ptr(const Type) and shared_ptr(Type) will share the ownership,
they provide a constant view and a modifiable view of the object, respectively. shared_ptr<Foo> is also convertible to shared_ptr<const Foo> (but not the other way round, you'd use const_pointer_cast for that (with caution). You should always default to accessing objects as constants, and only working with non-constant types when there's an explicit need for it.
If a method doesn't modify something, make it self-document that fact by having it accept a reference/pointer to const something instead.

Smart pointers are used to make sure that an object is deleted if it is no longer used (referenced).
Smart pointer are there to manage lifetime of the pointer they own/share.
You can think of a wrapper that has a pointer inside. So the answer is no. However you can access to the pointer they own via get() method.
Please note that it is not so difficult to make dangling pointers if you use get method, so if you use it be extra cautious.

Related

Pass in unique pointer for inherited class to constructor with unique pointer for base class?

Is it possible to do the following: I have an inherited class B from base class A. I want to create a constructor for a method that takes in a unique pointer to class A but still accept unique pointers to class B, similar to pointer polymorphism.
void Validate(unique_ptr<A> obj) {obj->execute();}
...
unique_ptr<B> obj2;
Validate(obj2);
This doesn't seem to work as I've written it (I get a No matching constructor for initialization error), but I wonder if this is still possible?
Your issue doesn't really have anything to do with polymorphism, but rather how unique_ptr<> works in general.
void Validate(unique_ptr<A> obj) means that the function will take ownership of the passed object. So, assuming that this is what the function is meant to do, you need to handoff said ownership as you call it.
In the code you posted, you would do this by moving the existing std::unique_ptr<>. This will ultimately (as in not by the call to std::move() itself, but the handoff as a whole) null-out the original pointer. That's the whole point of unique_ptr<> after all: There can only be one of them pointing at a given object.
void Validate(unique_ptr<A> obj) {obj->execute();}
...
unique_ptr<B> obj2;
Validate(std::move(obj2));
// obj2 is now null.
By extension, if Validate() is not meant to take ownership of obj, then it should not accept a unique_ptr<> in the first place. Instead, it should accept either a reference or a raw pointer depending on whether nullptr is an expected valid value:
Ideally:
void Validate(A& obj) {
obj.execute();
}
...
unique_ptr<B> obj2;
Validate(*obj2);
Alternatively:
void Validate(A* obj) {
if(obj) {
obj->execute();
}
}
...
unique_ptr<B> obj2;
Validate(obj2.get());
You cannot copy a unique pointer.
If you wish to transfer the ownership to the Validate function, then you must move from the unique pointer:
Validate(std::move(obj2));
A unique pointer parmeter accepted by Validate implies that it takes ownership, but that design sounds odd given the name of the function - but that may be due to missing context.
If ~A isn't virtual, then you may not use std::unique_ptr<A> because it would try to destroy the object through a pointer to the base which would result in undefined behaviour. You could use a custom deleter in such case.
If you don't wish to transfer ownership but instead the function should just access the object, then don't use a unique pointer parameter in the first place. Use a reference instead:
void Validate(A& obj) {
obj.execute();
}
It doesn't matter whether the caller has a smart pointer or even whether the object is allocated dynamically.
You can use a bare pointer if you need to represent null, but if you don't need it (as is implied by your attempted implementation), then it's better to use reference since being able to avoid checking for null makes it easier to write a correct program.

Why does std::unique_ptr not have a const get method?

I understand that std::unique_ptr is the way it is and probably won't be changed to break backwards compatibility but I was wondering if anyone has a good reason why the writers of the spec didn't overload the get method with a const variant that looks like
const T* get() const;
to follow the intent of the unique_ptr being const.
My best guess is that it is trying to mirror pointers and act like a T* const instead of a typical class. As a follow-up question, if I wanted to hold a pointer in a const-like fashion in a const instance of my class, should I be using something else other than std::unique_ptr to hold the data?
Update
In my case I want to protect myself from misusing the pointer in the class itself. I was writing a const move constructor MyClass(const MyClass&& other) and was copying the data from the new instance into other via std::copy. It took a long time to track down the bug because I had assumed the copy must be correct because of const protection. I'm trying to figure out what I could have done to protect myself from this outside of providing a const getter and using that within the class when doing the copy.
Smart pointers are pretending to be a raw pointer.
If you have class member which is raw pointer and use it in const method that you can't update a pointer, but you can modify object which is pointed.
Same behavior is desired for smart pointer. So std::unique_ptr::get is a const method, but doesn't force to return pointer to const object.
Note also that you can have a pointer to const object.
MyClass *pointerToObject
std::unique_ptr<MyClass> smartPointerToObject;
// but you can have also a case
const MyClass *pointerToConstObject
std::unique_ptr<const MyClass> smartPointerToConstObject;
In last case std::unique_ptr::get will return something you are expecting.
Based on comment below:
Just provide private methods:
InnerClass& GetField() { return *uniquePtrToInnerClass; }
const InnerClass& GetField() const { return *uniquePtrToInnerClass; }
And use it in your code and you will have const object of inner class in const method.
There's no point to giving read-only access to an object via its unique_ptr. You only pass unique_ptr around when you are transferring ownership, for access to the object without an ownership transfer, call up.get() and pass a const T* to the function that should only read (or if the pointer is never nullptr, it's also reasonable to evaluate *(up.get()) and pass a const T&).
As a bonus, this allows you to use that function with objects stored on the stack, embedded inside another object, or managed with a smart pointer other than unique_ptr.
There's a good discussion of all the unique_ptr parameter passing cases (in/out, const/non-const, etc) here:
How do I pass a unique_ptr argument to a constructor or a function?
For the same reason a T*const when dereferenced is a T&, not a T const&.
Constness of pointer is distinct from pointness of pointed-to.
get is const, it does not modify the state of unique_ptr.
Its constness does not impact the constness of the contents.
There is the idea of smart pointers that propogate constness, but unique_ptr is not that beast.
std::experimental::propogate_const wraps a pointer-like object and makes const travel through it.
It, or something like it, may solve your problem.
Note that I find half the time when I try to have const propogate like this, I discover I was wrong. But this may not be the case here.
In general, the proper way to handle the guts of a T*const in a const manner is to pass a T const& (or the nullable variant T const*).
I think this concern is valid,
there should be 2 versions for each de-referencing functions,
e.g.
const T* get() const;
T* get();
enter code here
I know that purpose of providing "T* get() const" is to ease replace existing raw pointer usages.
But since uniq ptr denotes ownership, it is incorrect that some one being able to modify some thing OWNED by the object via a immutable(const) reference [assuming modifying something fully owned by a object is same as modifying the object itself - which is true if this was an object instead of a ptr].
May be best option would be std to provide another version of Uniq ptr which holds to above idiom (only other option may be to derive a new class from uniq ptr and provide 2 versions for de-referencing )
Because as far as the unique_ptr is concerned, getting the internal raw pointer reference is a const operation. Calling .get() and retrieving the internal raw pointer of a std::unique_ptr does not change the internal state of the std::unique_ptr object itself. So it seems the library designers elected to mark it const without attention to what could happen to the underlying object if they just return a straight non-const reference to it.
In fact, if you have a std::unique_ptr inside an object, and you call a const member function of that object, you can still call non-const member functions on the internal std::unique_ptr inside that object. For example:
struct A {
void Const() const { }
void nonConst() { }
};
struct B {
std::unique_ptr<A> a;
void go() const {
a->nonConst(); // OK
}
};
Although you cannot perform non-const operations on the internal state variables of an object from one of its const member function, there is no rule that says you cannot perform non-const operations on other objects.
What you may be expecting is the constness promise to carry over from the unique_ptr to also apply to access to what it internally points to, so you'd expect unique_ptr to be written something like this:
template <typename T>
class cunique_ptr {
T* ptr;
public:
cunique_ptr() {
ptr = new T;
}
~cunique_ptr() {
delete ptr;
}
// You can only get a non-const pointer to the internals from a non-const object
T* get() { return ptr; }
// The const member function carries over the const promise to access to its internals
const T* get() const { return ptr; }
};
void test() {
cunique_ptr<A> a;
a.get()->nonConst();
const cunique_ptr<A> ca;
//ca.get()->nonConst(); //X fails: cannot call non-const member functions from const object
ca.get()->Const();
}
However, it seems the library designers elected against that type of protection and let the const promise be kind of shallow as it were.

Give Access to a Pointer's Data Without Revealing Pointer Address

I have a class that contains a pointer. I want to keep the user of the class from accessing the address of the pointer (so they can't set it to another address, delete it, or what-not). However, I would like the user to be able to modify the pointer data (or member data if it's not POD) as well as call the pointer's methods (assuming it has any).
Is there any way of returning a pointer or reference that allows you to change the data that a pointer points to without being able to change the pointer value itself?
So:
class A
{
public:
int Value;
void Method();
};
class Wrapper
{
public:
Wrapper()
{
Pointer = new A;
}
// Method that somehow would give access to the object without
// Allowing the caller to access the actual address
A* GetPointer()
{
return Pointer;
}
private:
A* Pointer;
};
int main()
{
Wrapper foo;
foo.GetPointer()->Value = 12; // Allowed
foo.GetPointer()->Method(); // Allowed
A* ptr = foo.GetPointer(); // NOT Allowed
delete foo.GetPointer(); // NOT Allowed
return 0;
}
I realize I could modify member data with getters and setters, but I'm not sure what to do about the methods (pass a method pointer maybe?) and I'd like to know if there is a better way before I accept a solution that I personally think looks messy.
It's not possible. The whole reason why ->Value is legal is because the expression to the left is a (smart) pointer to A*.
Obviously, with a non-smart pointer you already have your A* right there. Since raw pointers are not user-defined types, you cannot mess with the overload resolution.
With a smart pointer, (*ptr).Value has to work. That means you have to return a A& from operator* which in turn means that &(*ptr) gets you the traw pointer from a smart pointer.
There's even std::addressof for classes that try to block operator&.
You could make a getter That returns a reference to the object, ex:
A &GetObject()
{
return *Pointer;
}
This allows full access to the pointed-to object without providing access to the pointer itself at all.

Inside the copy constructor of shared_ptr

I have some confusion about the shared_ptr copy constructor. Please consider the following 2 lines:
It is a "constant" reference to a shared_ptr object, that is passed to the copy constructor so that another shared_ptr object is initialized.
The copy constructor is supposed to also increment a member data - "reference counter" - which is also shared among all shared_ptr objects, due to the fact that it is a reference/pointer to some integer telling each shared_ptr object how many of them are still alive.
But, if the copy constructor attempts to increment the reference counting member data, does it not "hit" the const-ness of the shared_ptr passed by reference? Or, does the copy constructor internally use the const_cast operator to temporarily remove the const-ness of the argument?
The phenomenon you're experiencing is not special to the shared pointer. Here's a typical primeval example:
struct Foo
{
int * p;
Foo() : p(new int(1)) { }
};
void f(Foo const & x) // <-- const...?!?
{
*x.p = 12; // ...but this is fine!
}
It is true that x.p has type int * const inside f, but it is not an int const * const! In other words, you cannot change x.p, but you can change *x.p.
This is essentially what's going on in the shared pointer copy constructor (where *p takes the role of the reference counter).
Although the other answers are correct, it may not be immediately apparent how they apply. What we have is something like this:
template <class T>
struct shared_ptr_internal {
T *data;
size_t refs;
};
template <class T>
class shared_ptr {
shared_ptr_internal<T> *ptr;
public:
shared_ptr(shared_ptr const &p) {
ptr = p->ptr;
++(ptr->refs);
}
// ...
};
The important point here is that the shared_ptr just contains a pointer to the structure that contains the reference count. The fact that the shared_ptr itself is const doesn't affect the object it points at (what I've called shared_ptr_internal). As such, even when/if the shared_ptr itself is const, manipulating the reference count isn't a problem (and doesn't require a const_cast or mutable either).
I should probably add that in reality, you'd probably structure the code a bit differently than this -- in particular, you'd normally put more (all?) of the code to manipulate the reference count into the shared_ptr_internal (or whatever you decide to call it) itself, instead of messing with those in the parent shared_ptr class.
You'll also typically support weak_ptrs. To do this, you have a second reference count for the number of weak_ptrs that point to the same shared_ptr_internal object. You destroy the final pointee object when the shared_ptr reference count goes to 0, but only destroy the shared_ptr_internal object when both the shared_ptr and weak_ptr reference counts go to 0.
It uses an internal pointer which doesn't inherit the contests of the argument, like:
(*const_ref.member)++;
Is valid.
the pointer is constant, but not the value pointed to.
Wow, what an eye opener this has all been! Thanks to everyone that I have been able to pin down the source of confusion to the fact that I always assumed the following ("a" contains the address of "b") were all equivalent.
int const *a = &b; // option1
const int *a = &b; // option2
int * const a = &b; // option3
But I was wrong! Only the first two options are equivalent. The third is totally different.
With option1 or option2, "a" can point to anything it wants but cannot change the contents of what it points to.
With option3, once decided what "a" points to, it cannot point to anything else. But it is free to change the contents of what it is pointing to. So, it makes sense that shared_ptr uses option3.

Passing a smart pointer as argument inside a class: scoped_ptr or shared_ptr?

I have a class that creates an object inside one public method. The object is private and not visible to the users of the class. This method then calls other private methods inside the same class and pass the created object as a parameter:
class Foo {
...
};
class A {
private:
typedef scoped_ptr<Foo> FooPtr;
void privateMethod1(FooPtr fooObj);
public:
void showSomethingOnTheScreen() {
FooPtr fooObj(new Foo);
privateMethod1(fooObj);
};
};
I believe the correct smart pointer in this case would be a scoped_ptr, however, I can't do this because scoped_ptr makes the class non copyable if used that way, so should I make the methods like this:
void privateMethod1(FooPtr& fooObj);
privateMethod1 doesn't store the object, neither keeps references of it. Just retrieves data from the class Foo.
The correct way would probably be not using a smart pointer at all and allocating the object in the stack, but that's not possible because it uses a library that doesn't allow objects on the stack, they must be on the Heap.
After all, I'm still confused about the real usage of scoped_ptr.
One further possibility is to create the object as a static_ptr for ease of memory management, but just pass the raw pointer to the other private methods:
void privateMethod1(Foo *fooObj);
void showSomethingOnTheScreen() {
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(fooObj.get());
};
I would use scoped_ptr inside showSomethingOnTheScreen, but pass a raw pointer (or reference) to privateMethod1, e.g.
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(fooObj.get());
Use here simple std::auto_ptr as you can't create objects on the stack. And it is better to your private function just simply accept raw pointer.
Real usage is that you don't have to catch all possible exceptions and do manual delete.
In fact if your object is doesn't modify object and your API return object for sure you'd better to use
void privateMethod1(const Foo& fooObj);
and pass the object there as
privateMethod1(*fooObj.get());
I'm suspicious about the comment "it uses a library that doesn't allow objects on the stack, they must be on the Heap."
Why? That typically means that they must be deallocated in some special way - so perhaps none of these solutions will work.
In that case, you only have to replace the allocation mechanism.
Create the object on the heap, but pass the object as reference to private methods.
class A {
private:
void privateMethod1(Foo& fooObj);
public:
void showSomethingOnTheScreen() {
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(*(fooObj.get()));
};
};