i'm using the new smart-pointer from C++ 11. I'm now confused what's the best way to pass and input value to an function.
The standard rule for method/function signatures is
inputs: prefer const reference and pointer where you must (f.e. nullptr is a legal input)
outputs: should b e pointers.
But with smart-pointer things are more "complicated".
I understand that you should not pass the input as ...
unique_ptr where the ownership is not transfered
shared_ptr where the object should not be share the ownership.
... and use referece or pointer instead.
For me the problem with the standard rule is that the developer who is using the function must dereference the pointer from the smart-pointer and he should always check if the result is not nullptr, so there is an "always" manual checking code.
void foo(const MyClass& obj)
{
...
}
void main()
{
auto a = make_unique<MyClass>();
if(*a) // always check dereference
{
foo(*a);
}
}
Instead, passing the input as const pointer, the usability is easier, but nullptr would be an "legal" value.
void foo(const MyClass* obj)
{
...
}
void main()
{
auto a = make_unique<MyClass>();
foo(a.get()); //easier to use, but nullptr is a "legal" value
}
Can anybody share his opinion when you use pointer, when references and how do you deal with deref's in that case.
Thanks in advance
If you are trying to check if the pointer points to an allocated object or if it is instead null, use std::unique_ptr::operator bool which will return true if the pointer is valid and false if there is no object created yet:
http://en.cppreference.com/w/cpp/memory/unique_ptr/operator_bool
This is better, and simpler, than using get() for this purpose.
Generally, with unique_ptr you do not pass the smart pointer itself to any functions, but when you want to pass a true pointer, you pass the return of get(), which is a non-owning normal pointer that the non-owning function can use. The pointer is still managed by the owning smart pointer. Common C++ guidelines encourage use of a normal pointer only for non-owning functions or classes that receive this pointer from a smart pointer elsewhere.
Related
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.
I implemented a C-API for a C++ class which uses shared-pointers of other objects to access them.
In my C-API I can of course only get raw pointers.
So I "convert" the raw pointer in my C-API to a shared-pointer and use this then with my C++ class methods:
method(std::shared_ptr<dataType>(raw-pointer));
Now I have the problem that at the end of "method" always the shared-pointer destructor is called and it unfortunately kills the object my raw-pointer is pointing at (which I don't want).
So, how can I prevent the raw-pointer from being killed?
I already tried shared-pointer functions like reset() or swap(), but they all didn't let my raw-pointer go...
bool Traffic_doStep(traffic_handle t, environment_handle e, double cycletime) {
if (!valid(t, __FUNCTION__)) return false;
if (!valid(e, __FUNCTION__)) return false;
if (!valid(cycletime, __FUNCTION__)) return false;
try {
t->doStep(std::shared_ptr<Environment>(e), cycletime);
return true;
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return false;
}
}
Expected result would be that the raw-pointer e is still pointing to a valid object after this function returned.
Actually the raw-pointer points then to a deleted object.
Don't put the pointer in a std::shared_ptr
The purpose of Smart Pointers in C++ is to provide automatic Lifetime management. When you write std::shared_ptr<int> ptr{raw_ptr};, the expectation is that when ptr goes out of scope, the object pointed to by raw_ptr will be delete'd. If this is not the intent, then you should not be placing the pointer in a smart pointer.
So if your application does not manage the lifetime of a pointer, then it is perfectly acceptable to store a raw pointer.
If the API behind the function cannot be altered, you will instead need to construct the std::shared_ptr with a no-op deleter function, so that when clean-up is called, nothing will happen to the pointer.
try {
std::shared_ptr<Environment> temp_ptr{e, [](int *) {}/*No-Op Deleter*/};
t->doStep(temp_ptr, cycletime);
return true;
}
This will solve your problem, but this is, of course, an Antipattern; don't do this unless you've been forced to by API design constraints that you cannot control.
You may provide a custom deleter of a shared pointer.
Here is a viable constructor:
template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );
But I would rather use a unique pointer and then release it.
I have a pre-existing function in an external library, which looks like this;
bool CreateTheThing(MyThing *& pOut);
In short; I give it a raw pointer (by reference), and the function allocates memory and assigns my pointer to the newly-allocated object. When the function returns, it is my responsibility to free the memory, when I'm done.
Obviously, I'd like to store this result into a unique_ptr<MyThing>, and avoid the manual delete.
I could create a temporary raw pointer to use with the API call, and pass it into the constructor for the unique_ptr;
MyThing* tempPtr;
CreateTheThing(tempPtr);
unique_ptr<MyThing> realPtr = unique_ptr<MyThing>(tempPtr);
Is there a more direct method than this? One which doesn't require a temporary raw pointer? Ideally, there would be a method of unique_ptr which exposes its internal pointer in a way that could work directly with the CreateTheThing method?
unique_ptr<T>::get() does not allow this, to my knowledge. The pointer it returns is not a reference to the internally-used pointer.
You can save one line of code (potentially many times) by writing many lines of code once:
class Wrapper
{
std::unique_ptr<MyThing> &u;
MyThing *p;
public:
Wrapper(std::unique_ptr<MyThing> &u) : u(u), p() {}
operator MyThing* & ()
{ return p; }
~Wrapper()
{ u.reset(p); }
};
Usage:
std::unique_ptr<MyThing> u;
CreateTheThing(Wrapper(u));
Is there a more direct method than this? One which doesn't require a temporary raw pointer?
No, there isn't.
Ideally, there would be a method of unique_ptr which exposes its internal pointer in a way that could work directly with the CreateTheThing method? unique_ptr::get() does not allow this, to my knowledge.
Your knowledge is correct. That would defeat the whole purpose of the std::unique_ptr, therefore unique_ptr::get() is a const function and the pointer is returned by value.
However similar as your constructor example, you can always use std::unique_ptr::reset() to pass an externally allocated pointer.
Also note: If the 3rd party API requires you to release the memory using free() you may need to provide a special deleter function for the std::unique_ptr.
If you use the function often you could put the conversion in a function.
Best would be to change the API, but this can also work.
inline std::unique_ptr<MyThing> CreateTheThing()
{
MyThing* p;
if (CreateTheThing(p))
{
return std::unique_ptr<MyThing>(p);
}
return std::unique_ptr<MyThing>();
}
You could also make this overload to make refactoring even easier:
inline bool CreateTheThing(std::unique_ptr<MyThing>& ptr)
{
try
{
MyThing* p;
if (CreateTheThing(p))
ptr = std::unique_ptr<MyThing>(p);
else
return false;
}
catch (std::bad_alloc&)
{
return false;
}
return true;
}
I'd like to optimize my code. I have one class that has a shared_ptr data member. In some methods of this class, I create objects that need to use this member (just to get information from the object pointed by shared_ptr). I know that lifetime of these created objects is lower than in my main class.
How to pass this pointer? I think another shared_ptrs is unnecessary (because I have a warranty that the object will exist). So what should get my created classes? Should they get raw pointer? Weak_ptr? Or the best solution is getting shared_ptr (and incrementing its reference counter)? What is the most standard solution?
In this case when you know the life-time of your shared resource will outlive those that you pass the pointer to the correct thing to do is pass a reference or a raw pointer:
void func(object* o)
{
// do stuff with o
}
// ...
std::shared_ptr<object> sp;
// ...
func(sp.get()); // pass raw pointer
The main reason for this is that the function can be useful no matter what kind of smart pointer is managing the resource. By accepting the raw pointer your function is able to accept objects from shared pointers as well as unique pointers and any other third party smart pointer.
There is no benefit to passing in the smart pointer unless the function needs to modify the smart pointer itself.
A good set of guidelines being produced by Bjarne Straustrup & Herb Sutter can be found here: CppCoreGuidelines
The rule about passing raw pointers (or references):
F.7
Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead.
Passing by smart pointer restricts the use of a function to callers that use smart pointers. A function that needs a widget should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
When passing the shared_ptr into a function that will not store the resource, pass it by reference:
void foo(const shared_ptr<T>& ptr)
{
// Basically just a pointer dereference
std::cout << ptr->bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(ptr);
}
That won't increment the reference count, but that's fine — you're effectively treating it as a raw pointer (because you're just temporarily inspecting the pointee) but in a way that's safe because if you accidentally copy it then you'll get the reference count increment that can save your life. :)
However, if foo needs to store any sort of handle to this object, then you should pass in the shared_ptr by copy … or consider using weak_ptr so that you at least get some semblance of safety.
The above contrived example is so simple that I'd actually make it the following:
void foo(const T& ptr)
{
std::cout << ptr.bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(*ptr.get());
}
Oh damn it I'm so stupid :-(,I could just use a bool array to reach the purpose
For example,I recieved a pointer p_class;
So how do I check if p_class points to a instantiated class?
I mean,even if the class was not been instantiated,every function of the class can still be called;and if I tried to access a variable in the class,I may access some illegal address and the program will crash
Well,I'm trying to write a network lib.
Since there are many protocols the lib have to support,
the_lib
{
public:
int selectProtocol(prtcl/*an enum*/ p)
{
switch(p)
{
case tcp:
t=new tcp;
....
}
}
int setTCP(opt,para)
{
switch(opt)
{
case csum:
t->setcsum(para)
break;
....
}
int setUDP(opt,para);
....
private:
TCP *t=0;
UDP *u=0;
...
}
Thus if the user select UDP at first but call setTCP, I have to determine whether to actually call the function in class TCP or not
0. The best thing to do? Don't use pointers.
MyClass instance;
instance.do_something(); // guaranteed to be safe to call
But if you need to refer to some object, then use references! In a well-formed piece of code, references are guaranteed to be pointing to some object, and thus any method you wish to call are guaranteed safe to be called.
But in those cases where you really need to use pointers, then:
1. Don't use raw pointers. Use smart pointers.
std::unique_ptr is almost always the best smart pointer for most of your cases. If you need shared semantics, then use std::shared_ptr. But remember: always prefer std::unique_ptr.
The good thing with most smart pointers is that they already do some default initialization for you when they are constructed without being initialized. Mostly, they set their internal pointer representation to nullptr.
2. Don't need ownership of an object? Just want to keep a reference but want to be able to set nullptr?
Use boost::optional<T&>. boost::optional has a specialization for references whose interface is very much like that of a pointer, but only much safer, as it does the same initialization technique as those of smart pointers.
3. Really need to use raw pointers for some unimaginable reason? Then always set it to nullptr when it's not meant to point to some object.
MyClass* p_instance = nullptr;
// Use p_instance, perhaps assign to it
p_instance = nullptr; // You don't need to use the pointed-to object
The gist of the above three techniques is this: because a pointer with a value of nullptr does not point to some valid object, then you can use it to check whether the pointer points to a valid object or not.
In this way your code can check if it's not initialized (p_instance == nullptr) or not (p_instance != nullptr). Also, the use of nullptr increase your chances of getting a runtime error when doing something on an invalid object, though the behavior is very much implementation dependent.
The general pattern for checking and using a pointer would be:
if(ptr) {
ptr->do_something();
}
But what if you really, really need to call do_something()? Then we are back to rule zero. :)
You can solve your problem by not using a bare pointer, and using a smart pointer instead. Both std::unique_ptr<> and std::shared_ptr<> have bool conversion operators that allow you to test if the pointer is valid or not.
class Foo { /* ... */ };
void foo (const std::unique_ptr<Foo> &p) {
if (!p) { /* ... */ }
}
void foo (const std::shared_ptr<Foo> &p) {
if (!p) { /* ... */ }
}
std::unique_ptr<Foo> p(new Foo);
std::shared_ptr<Foo> q = std::make_shared<Foo>();
If you are not performing dynamic allocation, then avoid pointers, and pass your object around to functions that take references.
void foo (const Foo &f) {
//...
}