I have a tricky syntax error which I cannot figure out. I am trying to run a function delegate where the context is a pointer to an object.
Syntax error:
((object)->*(ptrToMember)) // the compiler doesn't like the ->*
Where object is of the type Component*
And ptrToMember is of the type void (Component::*EventCallback) ()
Below is the code with the syntax error:
typedef void (Component::*EventCallback) ();
...
std::weak_ptr<Component> wc( mySharedPtr );
EventCallback ec = &Component::run;
((wc.lock())->*(ec))(); // syntax error
(wc.lock()->(*ec))(); // simpler version but still syntax error
// This is ok, but is there any significant time or memory involved in this reference object creation?
Component& wcc = *wc.lock();
(wcc.*ec)();
wc.lock() returns a std::shared_ptr<Component> but you are expecting it to return a raw Component* pointer instead. You cannot call the ->* on the std::shared_ptr itself. You have to ask it for the Component* pointer it is holding, and then you can use the ->* operator on that pointer, eg:
(wc.lock().get()->*ec)();
Since you are dealing with a std::weak_ptr, which could expire before you use it, you should make sure the Component object is actually available after locking before you try to access it:
if (auto sptr = wc.lock()) {
(sptr.get()->*ec)();
}
else {
// wc had expired
}
The result of wc.lock() is a shared_ptr. This is one of the few cases where the smart pointer diverges from a dumb pointer. shared_ptr does not implement operator ->*, so your first syntax can't work. (It's not a syntax error, you're just trying to do something shared_ptr doesn't support.)
You've found a workaround though.
Related
In a lambda function, instead of this, I was trying to use weak_ptr to access all member function and variable, but I'm getting this error:
operator -> or ->* applied to "const std::weak_ptr" instead of to a pointer type
std::weak_ptr<T> by design safely refers to an object which may or may not still exist. It does not offer operator-> or operator* since you have to make sure the object still exists before you can try to access it.
To access an object referred to by a std::weak_ptr you first call lock() which returns a std::shared_ptr. Then, you need to check if that std::shared_ptr refers to an object. If it does, then the object is safe to access and won't be deleted until that returned pointer is destroyed (because there will still exist a std::shared_ptr for it). If it doesn't then the std::weak_ptr was referring to a destroyed object which you can't access anymore.
Example :
#include <memory>
class foo
{
public:
void bar(){}
};
void test(std::weak_ptr<foo> ptr)
{
// Get a shared_ptr
auto lock = ptr.lock();
// Check if the object still exists
if(lock)
{
// Still exists, safe to dereference
lock->bar();
}
}
I am still exploring C++ 11. So I am pretty sure I am doing something wrong. But I just can't figure out the problem.
I have following Code:
MyClass::MyClass(const PlayerEventListener* eventListener)
{
weak_ptr<PlayerEventListener> _listener;
std::auto_ptr<PlayerEventListener> autoPtr;
autoPtr.reset(const_cast<PlayerEventListener*> (eventListener));
// I get error for this line
_listener = autoPtr;
}
I get following error: No viable overloaded '='
But following code compiles fine:
MyClass::MyClass(const PlayerEventListener* eventListener)
{
weak_ptr<PlayerEventListener> _listener;
std::shared_ptr<PlayerEventListener> sharedPtr;
sharedPtr.reset(const_cast<PlayerEventListener*> (eventListener));
// I get error for this line
_listener = sharedPtr;
}
Can somebody explain why I cannot convert a auto pointer to weak pointer?
weak_ptr is an object that holds a safe reference to an object actually held by shared_ptr, not auto_ptr. Therefore, there is no any overloaded operator= that could provide assigning auto_ptr to weak_ptr in the implementation of weak_ptr. It can be verified by compiling this example code and looking at the error
In constructor 'MyClass::MyClass(const PlayerEventListener*)':
21:14: error: no match for 'operator=' (operand types are 'std::weak_ptr<PlayerEventListener>' and 'std::auto_ptr<PlayerEventListener>')
Just to remember: According to http://www.cplusplus.com/reference/memory/auto_ptr/ :
This class template (auto_ptr) is deprecated as of C++11. unique_ptr is a new
facility with a similar functionality, but with improved security (no
fake copy assignments), added features (deleters) and support for
arrays. See unique_ptr for additional information.
I have
p2t::CDT* cdt = new CDT(p2d);
where p2d is an object that is passed by reference to the CDT class constructor.
I want to replace this with a smartpointer:
std::unique_ptr< p2t::CDT> cdt(p2d);
but it doesn't work in the way I wrote.
What is the correct way of writing the smart pointer for it?
After creating the smart pointer, do I use the pointer like a normal pointer (ie. (*cdt) gives me the object it points to, right? ) ?
you should use
std::unique_ptr<p2t::CDT> cdt(new p2t::CDT());
there is some documentation about it.
http://en.cppreference.com/w/cpp/memory/unique_ptr
About your question:
After creating the smart pointer, do I use the pointer like a normal pointer (ie. (*cdt) gives me the object it points to, right? ) ?
Yes, *cdt gives you object that it points too, because smart pointers overloads * operator.
And no, you cant use it like regular pointer, its a template class instance, so giving it to function like void foo(p2t::CDT * ptr); wont work.
BUT! there is a member function get() that will return normal pointer, which is wrapped into unique_ptr object that you can use with a such function.
void bar(Foo * ptr)
{
// some operations with ptr
}
std::unique_ptr<Foo> cdt(new Foo());
bar(cdt.get()); // can do so
Also, smart pointers overloads -> operator, so you can call methods of some class just like with regular pointer.
class Foo{
public:
void bar();
};
std::unique_ptr<Foo> ptr(new Foo());
ptr->bar(); // it works!
I got a structure and a function like the following:
struct MYOVERLAPPED : public OVERLAPPED
{
//...
};
void func1(std::unique_ptr<MYOVERLAPPED> pBuf)
{
//...
};
I am obtaining a pointer to MYOVERLAPPED which i want to pass to the func1-function.
The problem i encounter is, that no matter what i try i get the following errors :
What i did try already are the following:
Try1:
std::unique_ptr<OVERLAPPED> pOver(//....)
HandleAcceptIndication(std::move(pOver));
Error: Error 1 error C2440: 'initializing' : cannot convert from
'_OVERLAPPED **' to 'MYOVERLAPPED *'
Try2:
HandleAcceptIndication(new ACCEPT_OVERLAPPED);
Error 1 error C2664: 'HandleAcceptIndication' : cannot convert
parameter 1 from 'MYOVERLAPPED *' to 'std::unique_ptr<_Ty>'
Anyone knows how i can pass this casted pointer of OVERLAPPED to MYOVERLAPPED to the function and why Try2 does not work either since i casually use std::unique_ptr<MYOVERLAPPED> pO(new MYOVERLAPPED) which does work...?
While you cannot convert from std::unique_ptr<base> to std::unique_ptr<derived> directly, it is not too hard to write a cast function that will be safe (i.e. not leak the resource under any circumstance, and only succeed if the cast is valid:
template <typename Dst, typename Src>
std::unique_ptr<Dst> unique_dynamic_cast( std::unique_ptr<Src>& ptr ) {
Src * p = ptr.release(); // [1]
std::unique_ptr<Dst> r( dynamic_cast<Dst*>(p) ); // [2]
if ( !r ) {
ptr.reset( p ); // [3]
}
return r; // [4]
}
The basic idea is that we need to extract the pointer from the std::unique_ptr and set it aside in [1]. We cannot try dynamic_cast directly, as if that fails, ptr would have released ownership, and the memory would be leaked. Then we try and perform the dynamic_cast [2] from the local pointer to the requested type of pointer and pass ownership onto the r result unique pointer. If the dynamic_cast fails, then r will be null, and we need to return ownership of the memory to the original std::unique_ptr [3], for calling code to decide what to do with it. We then return the converted std::unique_ptr to the caller in [4].
This doesn't work because you're trying to cast the wrong way in the inheritance hierarchy. You're trying to convert from Base* to Derived* implicitly.
unique_ptr<A> and unique_ptr<B> are unrelated types. You can't convert between them unless an implicit conversion exists between A* and B* (thanks UncleBens), which is not true in this case. Also you should not cast down the inheritance hierarchy with an instance that is not the subclass you are casting to. In this case, you're trying to cast a OVERLAPPED to a MYOVERLAPPED which is an invalid cast because an OVERLAPPED is not a MYOVERLAPPED. That's why you can't convert between the unique_ptr types in the first place.
If you are just trying to pass a unique_ptr to func1, you can do it like this:
func1(shared_ptr<MYOVERLAPPED>(new MYOVERLAPPED));
Also, by passing a unique_ptr to a function, the pointer in the original one gets set to NULL. Consider using references or shared_ptrs if you are not creating the unique_ptr as a temporary and passing it to the function and you need to use the same instance later.
In Scott Meyers's Effective C++, item 18 Make interfaces easy to use correctly and hard to use incorrectly, he mentioned the null shared_ptr:
std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment)
and a vogue assignment operation
pInv = ... //make retVal point to the correct object
In which case one may need to create a null shared_ptr and do assignment later? Why not just create the shared_ptr whenever you have the resources (raw pointer)?
Since Scott Meyers did not show the complete assignment in the previous example, I thought the shared_ptr's assign operator is overloaded that one can do this:
pInv = new Investment; // pInv will take charge of the pointer
// but meanwhile keep the delete function it already had
But I tried with boost's implementation it doesn't work this way. Then what is the sense to have null shared_ptr?
I am almost sure that I am missing something here, someone help me out of it please.
ps. more about the initialization and assignment of a shared_ptr
#include <boost/shared_ptr.hpp>
int main(int argc, char *argv[])
{
boost::shared_ptr<int> ptr1(new int);
boost::shared_ptr<int> ptr2;
ptr2.reset(new int);
boost::shared_ptr<int> ptr3 = new int;
return 0;
}
this example can not be compiled by g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 and the latest boost:
sptr.cpp: In function ‘int main(int, char**)’:
sptr.cpp:8:39: error: conversion from ‘int*’ to non-scalar type ‘boost::shared_ptr<int>’ requested
There is no need to use that hack to get a null (empty) shared_ptr. Simply use the default constructor:
std::shared_ptr<Investment> pInv; // starts null
To assign a pointer to a shared_ptr, either do it at construction time:
std::shared_ptr<Investment> pInt(new Investment);
// not allowed due to explicit annotation on constructor:
// std::shared_ptr<Investment> pInt = new Investment;
Or use the .reset() function:
pInt.reset(new Investment);
It's possible that the author of that article may have intended to provide a custom deleter (getRidOfInvestment). However, the deleter function is reset when .reset() is called, or when otherwise the inner pointer is changed. If you want a custom deleter, you must pass it to .reset() upon creation of the shared_ptr.
One pattern you might want to use to make this more foolproof is a custom creation function:
class Investment {
protected:
Investment();
// ...
public:
static shared_ptr<Investment> create();
};
shared_ptr<Investment> Investment::create() {
return shared_ptr<Investment>(new Investment, getRidOfInvestment);
}
Later:
shared_ptr<Investment> pInv = Investment::create();
This ensures you will always have the correct destructor function attached to the shared_ptrs created from Investments.
It's the same reason to have a null raw pointer - e.g.
say you have:
typedef std::tr1::shared_ptr<Investment> InvestmentPtr;
map<key,InvestmentPtr> portfolio;
...
get(mykey) {
iterator it = portfolio.find(mykey);
if (it == portfolio.end())
return InvestmentPtr();
else
return it->second;
}
}
This allows you to do:
InvestmentPtr p = get(key);
if (p) ...
There are tons of reasons you might like objects to be default constructible. First and foremost you'd like the smart pointer to be as similar as possible to a raw pointer, and since you can say int * p; (and get an undefined, uninitialized pointer), you can also say shared_ptr<int> p; and get a pointer that doesn't point anywhere (but you get to test it with !).
One of the most compelling reasons is possibly that you can make containers with shared_ptrs, and you can fill the containers without assigning pointees right there and then.