Okay, so let's say I have some random abstract base class Base and I have a class Foo which contains a pointer to this base class as a datamember. So
class Foo
{
public:
Foo(Base*);
private:
Base* ptr;
}
Now the reason I use a pointer to the base class is because I want to be able to choose which derived class my Foo object has a pointer to. Now the tricky part is, to me, the implementation of the constructor for Foo.
If I do it like this
Foo::Foo(Base* _ptr)
{
Foo::ptr = _ptr;
};
it would be possible for the user to adjust the object pointed to by Foo::ptr since _ptr will still exist after the constructor has finished. I cannot make the object pointed to by _ptr constant because Foo::ptr needs to update itself regularly. Now I was thinking about adding a line _ptr = NULL at the end of the constructor, but that could be dangerous as well, since the user could try to dereference _ptr.
The only way I can think of to make this work is to make a copy of the object pointed to by _ptr and initializing Foo::ptr to the address of that copy. But then the object pointed to by _ptr would need to have a member function Clone() or something similar because I can't call the copy constructor for an object of which I don't know the class at compile-time.
So is there any elegant way of doing this if there is no Clone()? Or is that really the only possibility?
Construct from a unique_ptr. That way your user has no access to the pointer after it has been used in the creation of a Foo object (unless he really wants to and uses get).
e.g.
#include <memory>
struct Bar {};
struct Foo {
Foo(std::unique_ptr<Bar>&& ptr) : ptr_(std::move(ptr)) {}
std::unique_ptr<Bar> ptr_;
};
int main()
{
std::unique_ptr<Bar> tt(new Bar());
Foo f(std::move(tt));
return 0;
}
An alternative is using smart pointers. That way, ownership is assigned to the smart pointer implementation.
Related
I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.
I have a base class with a pointer member. I would have to make an educated guess to determine whether it should be an unique_ptr or a shared_ptr. None of them seems to solve my particular use case.
class Base
{
public:
Base(): pInt(std::unique_ptr<int>(new int(10))) {};
virtual std::unique_ptr<int> get() = 0;
//Base(): pInt(std::shared_ptr<int>(new int(10))) {}; // Alternate implementation
//virtual std::shared_ptr<int> get() = 0; // Alternate implementation
private:
std::unique_ptr<int> pInt;
//std::shared_ptr<int> pInt; // Alternate implementation
};
The base class has been derived onto Derived1 and Derived2. The former returns the unique_ptr member pInt where the later returns a local unique_ptr object.
class Derived1: public Base
{
public:
Derived1() {};
virtual std::unique_ptr<int> get()
{
//return std::move(pInt); Will compile but the ownership is lost
return pInt;
}
private:
std::unique_ptr<int> pInt;
};
class Derived2: public Base
{
public:
Derived2() {};
virtual std::unique_ptr<int> get()
{
std::unique_ptr<int> pInt(new int());
return pInt;
}
private:
std::unique_ptr<int> pInt;
};
Derived1's implementation of get would not implicitly transfer the ownership as the member pointer variable is not an eXpiring value, where as the Derived2's implementation can. This behaviour is well documented in the standard
see 12.8 §34 and §35:
When certain criteria are met, an implementation is allowed to omit
the copy/move construction of a class object [...] This elision of
copy/move operations, called copy elision, is permitted [...] in a
return statement in a function with a class return type, when the
expression is the name of a non-volatile automatic object with the
same cv-unqualified type as the function return type [...]
When the criteria for elision of a copy operation are met and the
object to be copied is designated by an lvalue, overload resolution to
select the constructor for the copy is first performed as if the
object were designated by an rvalue.
Nevertheless, if I explicitly transfer the ownership via the std::move, the member pointer would be unusable in the future.
Alternatively, I would have to make the definition of the pointer as shared_ptr but that would be an extra overhead for the implementation of Derived2::get.
Note It should be considered that the occurrence of Derived2::get is more compared to Derived1::get so the design decision of using std:: shared_ptr can have a considerable relative impact.
Your Derived1 case cannot be handled the way you want by unique_ptr. You want multiple smart pointers to the same resource. unique_ptr is simply not an option for that. There's no way around that.
You could stick with a unique_ptr member, but make your function return a raw pointer.
virtual int *get() = 0;
This is troublesome for your Derived2 class, because it is not clear whether the caller should free the pointed-to memory. I recommend you do not do this.
You could use a shared_ptr member, as you suggested, and make your function return that. This is fully functional in your Derived2 class, but as you point out, sub-optimal.
It is still the cleanest solution, though. For callers that only know they've got a Base, you need some way of informing them (either manually or through the returned type) what they should do when they're done with get()'s result, so you cannot return unique_ptr<int> anyway.
The only way a function returning unique_ptr<int> could be useful is if the caller already knows you've got a Derived2. But then, you can just add a new member:
virtual shared_ptr<int> get() {
return get_unique();
}
virtual unique_ptr<int> get_unique() {
std::unique_ptr<int> pInt(new int());
return pInt;
}
I would only do that if profiling shows that the shared_ptr<int> get() member actually adds measurable overhead, though. There's a good chance that your shared_ptr<int> implementation is sufficient, performance-wise, and then readibility should probably be a reason for not adding a new member.
The purpose of unique_ptr is to point to a resource from a unique place. If you need to point to this resource from multiple places, unique_ptr is no longer appropriate. You should use shared_ptr in that case.
If releasing ownership of the resource is appropriate for your logic, then just use:
unique_ptr<int> get()
{
return move(pInt);// this will move the ownership of the resource away from the member field
}
... but from now on, the pInt is no longer valid.
If you are careful with resources (if you are not worried of dangling pointers), than just return raw pointer to the resource (but please don't prefer this to use of shared_ptr).
In case of using shared_ptr, be careful of cyclic dependency, use weak_ptr do counter it. Here is something about it: http://geekwentfreak-raviteja.rhcloud.com/blog/2014/07/06/c11-how-to-create-cyclic-dependencies-with-shared_ptr-and-how-to-avoid-them/?_sm_au_=irVM6PVF1TR4nGMW
Post edit:
When you use unique_ptr as a member field, you are loosing copy constructor, because unique_ptr cannot be copied. FYI
But still, use of unique_ptr seems to me as extra overhead already, in which just use shared_ptr or int directly.
Suppose I have a class called foo which inherits from a class called bar.
I have a std::unique_ptr to an instance of foo and I want to pass it to a function that only takes std::unique_ptr<bar>. How can I convert the pointer so it works in my function?
You can convert a std::unique_ptr<foo> rvalue to an std::unique_ptr<bar>:
std::unique_ptr<foo> f(new foo);
std::unique_ptr<bar> b(std::move(f));
Obviously, the pointer will be owned by b and if b gets destroyed bar needs to have a virtual destructor.
Nothing special is required because of the inheritance. You need to use std::move to pass the unique_ptr to a function, but this is true even if the types match:
#include <memory>
struct A {
};
struct B : A {
};
static void f(std::unique_ptr<A>)
{
}
int main(int,char**)
{
std::unique_ptr<B> b_ptr(new B);
f(std::move(b_ptr));
}
You may use this syntax:
std::unique_ptr<parent> parentptr = std::unique_ptr<child>(childptr);
Or you may use std::move.
The other option is to emit raw pointer, but you need to change a function:
void func(const parent* ptr)
{
// actions...
}
func(*childptr);
Here is a good article about smart pointers and passing it to functions: http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters.
You can't, because it would violate the most basic unique_ptr rule: there has to be only one instance that holds a given pointer, and the unique_ptr has full ownership of it (when it goes out of scope, the pointee is deleted).
unique_ptr<T> and unique_ptr<U> (where U : T) aren't compatible, as you've seen.
For shared_ptr, for which you can have multiple instances, there is std::static_pointer_cast that behaves just like a static_cast, except that it accepts a shared_ptr and returns another one (and both point to the same object).
If you absolutely need to use a unique_ptr, you'll have to create a function that first disowns your current unique_ptr and puts that pointer into a new one of the right type. You might also need to do the opposite conversion after your function call.
Let's say I have a class called MyClass, which has two member variables (both being int) called firstNumber_ and secondNumber_. This class also has a method called clone( ) which creates a new instance of the object with the same values and returns that new instance.
The question is, when returning a new instance of the class, do I return it as a pointer, a reference, or just the instance itself?
// MyClass.h
class MyClass {
private:
int firstNumber_;
int secondNumber_;
public:
MyClass( int numA, int numB ) {
firstNumber_ = numA;
secondNumber_ = numB;
}
~MyClass( ) { };
// This method creates a copy of the object and returns that object.
// The ( ? ) is there because I am not sure what type the returned value is.
MyClass ( ? ) clone( ) {
// Do I just return the new instance? Or do I need to return a reference or a pointer of the new instance?
return MyClass( firstNumber_, secondNumber_ );
}
};
What's the proper way of achieving this? Note that MyClass does not inherit from any other classes.
Thanks in advance.
The method clone() is usually for returning a pointer to an instance of a polymorphic type, so you can call it on a pointer of the base type and get an pointer to an instance of the right derived type. For simple copying, in C++ you use the copy constructor, not a clone method.
Clone method:
struct Base{};
struct Foo : Base
{
Base* clone() const { return new Foo(*this); }
}:
Base * b1 = new Foo;
...
Base * b2 = b1->clone(); // points to a Foo instance, copy of object pointed at by b1
Where the clone method us using the (compiler generated) copy constructor.
Using copy constructor:
Foo f1;
Foo f2 = f1; // copy assignment
In real code you should prefer smart pointers over the raw ones used in these examples.
Concerning the return value, by default you should return by value, although in the polymorphic clone() example this would defeat the purpose by slicing the return object into a Base. So we return a pointer to an instance allocated dynamically. The intent and ownership has to be clear: in this case, the caller owns the pointer, and is responsible for deallocating it. Pre-c++11 you would have to rely on documentation to convey this. In C++11 you can use the smart pointer std::unique_ptr, which enforces the ownership and states it clearly.
I have the following contrived example (coming from real code):
template <class T>
class Base {
public:
Base(int a):x(a) {}
Base(Base<T> * &other) { }
virtual ~Base() {}
private:
int x;
};
template <class T>
class Derived:public Base<T>{
public:
Derived(int x):Base<T>(x) {}
Derived(Derived<T>* &other): Base<T>(other) {}
};
int main() {
Derived<int> *x=new Derived<int>(1);
Derived<int> y(x);
}
When I try to compile this, I get:
1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27: instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error: initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’
1) Clearly gcc is being confused by the constructors. If I remove the reference
from the constructors, then the code compiles. So my assumption is that something goes wrong
with up-casting pointer references. Can someone tell me what is going on here?
2) A slightly unrelated question. If I were to do something horrendous like "delete other" in the constructor (bear with me),
what happens when someone passes me a pointer to something on the stack ?
E.g. Derived<int> x(2);
Derived<int> y(x);
where
Derived(Derived<T>*& other) { delete other;}
How can I make sure that pointer is legitimately pointing to something on the heap?
Base<T> is a base type of Derived<T>, but Base<T>* is not a base type of Derived<T>*. You can pass a derived pointer in place of a base pointer, but you can't pass a derived pointer reference in place of a base pointer reference.
The reason is that, suppose you could, and suppose the constructor of Base were to write some value into the reference:
Base(Base<T> * &other) {
Base<T> *thing = new Base<T>(12);
other = thing;
}
You've just written a pointer to something which is not a Derived<T>, into a pointer to Derived<T>. The compiler can't let this happen.
You cannot convert a reference to a pointer to Derived to a reference to a pointer to Base. (Templates don't contribute to the issue here, so removed from my example below.)
If you want to defer responsibility for a pointer, use a smart pointer type. Smart pointer types can represent the "responsibility to delete" that raw pointers cannot. Examples include std::auto_ptr and boost::shared_ptr, among many others.
Why you cannot upcast pointer references:
struct Base {};
struct Derived : Base {};
struct Subclass : Base {};
int main() {
Derived d;
Derived* p = &d;
Derived*& d_ptr = p;
Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is
Base b;
b_ptr = &b; // oops! d_ptr no longer points to a Derived!
Subclass s;
b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}
When you pass your 'other' parameter to the Base ctor, you're trying to do the same thing as b_ptr = d_ptr above.
You make sure that pointer points to something on the heap by writing that in your documentation and relying on the caller to abide by that. If whoever calls your constructor passes a stack pointer, all bets are off, and it's not your fault - you can try to catch the problem early, but no guarantees.
That's how the standard library works - often it'll catch obvious errors, but it's not required to, and it's up to the caller to make sure they're not doing anything stupid.
Your x variable is not a pointer, it should be if you want to assign a new Derived<int> to it.
As for deleting things on the stack, don't do it. There is no way to tell whether you have been passed the address of something on the stack or on the heap (indeed, the C++ standard doesn't even acknowledge the existence of a stack). The lesson here is that you shouldn't be deleting things that you don't own, especially if you have no way of telling where they came from.
Not sure why do you want reference to the pointer. Why not
Base(Base<T> * other) { }
and
Derived(Derived<T>* other): Base<T>(other) {}
That should work.
And, like other answered, I don't think you can legitimately know whether the pointer is pointing into heap.
Edit: why can't one do what you're trying to: consider example:
Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;
Where Derived1 and Derived2 are different classes derived from Base? Would you think it's legitimate? Now that x of type Derived1* points to Derived2?