This question relates to the DelayedCaller in this answer.
The DelayedCaller binds a function pointer and its arguments and works like a charm as long as the the arguments aren't pointers to things shorter-lived than the DelayedCaller's execution (think string.c_str() of a local variable as argument).
To circumvent this issue I created a storage for problematic arguments handled by a template function scanning the arguments.
What I need now is kinda the opposite: I want the member function to be called on a different object of the same type, by evaluating the the address of the pointer given to the DelayedCaller as an argument.
I currently see two ways to go about this:
std::placeholders: Instead of providing the object when creating the DelayedCaller it is provided with the call method.
a wrapper for the object pointer that dereferences twice (overloading ->).
I favor 2. over 1. (I don't want to have to provide an argument whenever using call()), but there might other options I am not even considering.
Example:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
class MyClass
{
float myFloat;
public:
MyClass(float f):myFloat(f){}
void myFunc(int arg1)
{
std::cout << arg1 << ", " << myFloat << '\n';
}
};
class MyContainer
{
public:
MyClass* object;
};
// DelayedCaller implementation
class DelayedCaller
{
public:
template <typename TFunction, typename... TArgs>
static std::shared_ptr<DelayedCaller> setup(TFunction&& a_func,
TArgs&&... a_args)
{
return std::shared_ptr<DelayedCaller>(new DelayedCaller(
std::bind(std::forward<TFunction>(a_func),
std::forward<TArgs>(a_args)...)));
}
void call() const { func_(); }
private:
using func_type = std::function<void()>;
DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
func_type func_;
};
int main()
{
MyContainer container;
MyClass* c1 = new MyClass(45.6);
container.object = c1;
// the next line is the critical one. Instead of myFunc being called
// on the current value of container.object, it should be called on
// the one container.object is holding when caller is called.
auto caller(DelayedCaller::setup(&MyClass::myFunc, container.object, 123));
caller->call();
MyClass* c2 = new MyClass(22.8);
container.object = c2;
caller->call();
delete c1;
delete c2;
return 0;
}
std::reference_wrapper might help, use:
auto caller(DelayedCaller::setup(&MyClass::myFunc, std::ref(container.object), 123));
Demo
How about leaving "binding" to C++ compiler with usage of lambda expression?
auto caller(DelayedCaller::setup([&container] { container.object->myFunc(123);}));
Gives the output:
123, 45.6
123, 22.8
PS. This lambda is directly convertible into std::function<void(void)>, thus DelayedCaller constructor could be public and created without setup function if wanted. If you can edit its implementation of course.
Your really need to understand what std::bind does.
When using std::bind, it will copy(or move respectively if they are respectively r-value, but as a reminder, whether they are moved depend on callable objects and each arguments feed into std::bind respectively)
Next, I'll discuss the situation when there's only one argument, but the rule of it applies to situation where there're more than one arguments respectively.
Both the callable object(which could be pointers to functions or functors) and the arguments into the object of std::function returned by std::bind, so it will never occur the case you asked.
If the argument is not a pointer, or reference, you can just feed the (temporary) objects into sts::bind and the c++ standard promises that it will only be copied or moved, not by reference unless you use std::ref or std::cref to wrap that object.
But if you feed std::unique_ptr or other things that wraps a pointer(or reference as shown in above), you need to consider them as a pointer(reference), not an object(although copy/move choices still occurs)
If the argument is a pointer, then the pointer will be copied into it.
Will, in this case, if the pointer points to a local variable, bingo, then you have one bug to track.
Actually the code you write will work well if (the destructor of the object does not do any damage to the object in the memory, in other word, the object exists after it is destructed, like POD and etc) && (the memory contains the object is not reused by any other objects, when sth like this (another function is called and its local variables occupies the memory of that object and write something to it) happens it is reused).
If the pointer points to sth you allocated on heap and it is not deallocated until your call of the DelayedCaller::cal is done, then there's nothing wrong with you code.
If the pointer is a constant pointer that points to a literal, then it will be all fine.
The case when the argument is a reference is roughly the same as the case when it's a pointer.
Reference: http://en.cppreference.com/w/cpp/utility/functional/bind
Related
Lets consider the following piece of code:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function:
void g()
{
std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
f(std::move(u_ptr));
X: u_ptr->do_sth(); // it works, I don't understand why. Details below.
}
I don't understand why u_ptr in line X is still alive.
After all I forced him to be moved (std::move).
---EDIT---
Ok, so now:
The code is still working:
class T{
public:
T(){}
void show(){
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my;
my->show();
f(std::move(my));
my->show(); // How is it possible. Now, f takes unique_ptr by value
return 0;
}
You didn't show us that code to function f, but presumably it didn't move the pointer, even though it had permission to.
You passed the unique_ptr by reference. If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to.
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. That value would be a unique_ptr for it to be moved into. In that case, you should declare the function as taking a std::unique_ptr<T> instead of a std::unique_ptr<T>&&. Then you can actually invoke the move constructor when you call the function.
Update: With your latest change, the unique_ptr would no longer reference any valid object due to the move construction. You just never check that it does. Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object. You also never made the unique_ptr actually point to anything.
Instead, make the unique_ptr point to something. After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. Like this:
#include <iostream>
#include <memory>
class T{
public:
T() : valid (true) {}
~T() { valid = false; }
bool valid;
void show(){
std::cout << "HEJ! " << valid << std::endl;
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my (new T); // Make it point to a new object
my->show();
f(std::move(my));
my->show(); // Try to access
return 0;
}
in the line f(std::unique_ptr<T>&& uptr) uptr is not an object - it's a reference. a reference which capable to catch temporeries and mutate them.
it's like asking why doesn't the object get cloned in the next example
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_ is passed by "regular" reference and won't get copied - this is what pass by reference means.
std::move only cast l-value to r-value-reference, which uptr in f(std::unique_ptr<T>&& uptr) can reference, it's a reference referencing an object. opposed to the common conception, std::move won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. operator to kick in.
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference.
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure.
The reason why your call to show doesn't crash is because it doesn't use the this pointer (it doesn't try to modify or access a data member).
Try this:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
This is the answer when you initially had your f function taking a rvalue reference &&.
Your function takes a rvalue reference. Therefore, no new unique_ptr object is created yet, you are simply passing a reference.
Inside your f function, if you create a a local unique_ptr, with the parameter uptr, then finally uptr will be moved to create that new object.
template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
//move uptr into local_unique_ptr
//note that we have to use move again
//because uptr has a name, therefore its a lvalue.
auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}
The important thing to always know is that std::move is simply a static_cast.
If you pass a lvalue to std::move, it returns a rvalue. If you pass a rvalue, it returns a rvalue. That's it.
Your function f may not in fact move the pointer. Merely taking an object by && does not modify the object.
u_ptr->do_sth() may invoke a static member function or a member function that does not access the object (this) and this is why it does not crash.
I want to create a class Bar that can distinguish between temporaries and non-const non-temporaries. According to this (about 25% down the page), I can get away with this if the second StealPointer takes a const reference (to a pointer in my case), but in my code it just uses the StealPointer(Foo*&& foo) version regardless of how it is called.
class Foo {};
class Bar {
public:
// For when StealPointer(new Foo()); is called. Bar instance then owns the
// pointer.
void StealPointer(Foo*&& foo) {} // Get the temporaries only.
// For when a Foo* already exists and is passed in StealPointer(my_foo_ptr);
// Takes ownership and invalidates the pointer that the caller once had.
void StealPointer(Foo*&) {} // Get lvalues only.
};
Can I do this? Is there a way to do this that only requires one function? If it matters, Bar is going to store the pointer in a unique_ptr and I would like to avoid the additional syntax of passing in a unique_ptr or making the caller do something with std::move. I can't just pass the pointers by reference, because temporaries of type Foo* can't be converted to Foo*&.
Make your function templated and let std::unique_ptr worry about those details for you.
template <typename Ptr>
void StealPointer(Ptr&& p) // a universal reference, matches *any* type of value
{
uniqptr = std::move(p); // Works for both rvalues and lvalues
}
I am new to C++ programming, but I have experience in Java. I need guidance on how to pass objects to functions in C++.
Do I need to pass pointers, references, or non-pointer and non-reference values? I remember in Java there are no such issues since we pass just the variable that holds reference to the objects.
It would be great if you could also explain where to use each of those options.
Rules of thumb for C++11:
Pass by value, except when
you do not need ownership of the object and a simple alias will do, in which case you pass by const reference,
you must mutate the object, in which case, use pass by a non-const lvalue reference,
you pass objects of derived classes as base classes, in which case you need to pass by reference. (Use the previous rules to determine whether to pass by const reference or not.)
Passing by pointer is virtually never advised. Optional parameters are best expressed as a std::optional (boost::optional for older std libs), and aliasing is done fine by reference.
C++11's move semantics make passing and returning by value much more attractive even for complex objects.
Rules of thumb for C++03:
Pass arguments by const reference, except when
they are to be changed inside the function and such changes should be reflected outside, in which case you pass by non-const reference
the function should be callable without any argument, in which case you pass by pointer, so that users can pass NULL/0/nullptr instead; apply the previous rule to determine whether you should pass by a pointer to a const argument
they are of built-in types, which can be passed by copy
they are to be changed inside the function and such changes should not be reflected outside, in which case you can pass by copy (an alternative would be to pass according to the previous rules and make a copy inside of the function)
(here, "pass by value" is called "pass by copy", because passing by value always creates a copy in C++03)
There's more to this, but these few beginner's rules will get you quite far.
There are some differences in calling conventions in C++ and Java. In C++ there are technically speaking only two conventions: pass-by-value and pass-by-reference, with some literature including a third pass-by-pointer convention (that is actually pass-by-value of a pointer type). On top of that, you can add const-ness to the type of the argument, enhancing the semantics.
Pass by reference
Passing by reference means that the function will conceptually receive your object instance and not a copy of it. The reference is conceptually an alias to the object that was used in the calling context, and cannot be null. All operations performed inside the function apply to the object outside the function. This convention is not available in Java or C.
Pass by value (and pass-by-pointer)
The compiler will generate a copy of the object in the calling context and use that copy inside the function. All operations performed inside the function are done to the copy, not the external element. This is the convention for primitive types in Java.
An special version of it is passing a pointer (address-of the object) into a function. The function receives the pointer, and any and all operations applied to the pointer itself are applied to the copy (pointer), on the other hand, operations applied to the dereferenced pointer will apply to the object instance at that memory location, so the function can have side effects. The effect of using pass-by-value of a pointer to the object will allow the internal function to modify external values, as with pass-by-reference and will also allow for optional values (pass a null pointer).
This is the convention used in C when a function needs to modify an external variable, and the convention used in Java with reference types: the reference is copied, but the referred object is the same: changes to the reference/pointer are not visible outside the function, but changes to the pointed memory are.
Adding const to the equation
In C++ you can assign constant-ness to objects when defining variables, pointers and references at different levels. You can declare a variable to be constant, you can declare a reference to a constant instance, and you can define all pointers to constant objects, constant pointers to mutable objects and constant pointers to constant elements. Conversely in Java you can only define one level of constant-ness (final keyword): that of the variable (instance for primitive types, reference for reference types), but you cannot define a reference to an immutable element (unless the class itself is immutable).
This is extensively used in C++ calling conventions. When the objects are small you can pass the object by value. The compiler will generate a copy, but that copy is not an expensive operation. For any other type, if the function will not change the object, you can pass a reference to a constant instance (usually called constant reference) of the type. This will not copy the object, but pass it into the function. But at the same time the compiler will guarantee that the object is not changed inside the function.
Rules of thumb
This are some basic rules to follow:
Prefer pass-by-value for primitive types
Prefer pass-by-reference with references to constant for other types
If the function needs to modify the argument use pass-by-reference
If the argument is optional, use pass-by-pointer (to constant if the optional value should not be modified)
There are other small deviations from these rules, the first of which is handling ownership of an object. When an object is dynamically allocated with new, it must be deallocated with delete (or the [] versions thereof). The object or function that is responsible for the destruction of the object is considered the owner of the resource. When a dynamically allocated object is created in a piece of code, but the ownership is transfered to a different element it is usually done with pass-by-pointer semantics, or if possible with smart pointers.
Side note
It is important to insist in the importance of the difference between C++ and Java references. In C++ references are conceptually the instance of the object, not an accessor to it. The simplest example is implementing a swap function:
// C++
class Type; // defined somewhere before, with the appropriate operations
void swap( Type & a, Type & b ) {
Type tmp = a;
a = b;
b = tmp;
}
int main() {
Type a, b;
Type old_a = a, old_b = b;
swap( a, b );
assert( a == old_b );
assert( b == old_a );
}
The swap function above changes both its arguments through the use of references. The closest code in Java:
public class C {
// ...
public static void swap( C a, C b ) {
C tmp = a;
a = b;
b = tmp;
}
public static void main( String args[] ) {
C a = new C();
C b = new C();
C old_a = a;
C old_b = b;
swap( a, b );
// a and b remain unchanged a==old_a, and b==old_b
}
}
The Java version of the code will modify the copies of the references internally, but will not modify the actual objects externally. Java references are C pointers without pointer arithmetic that get passed by value into functions.
There are several cases to consider.
Parameter modified ("out" and "in/out" parameters)
void modifies(T ¶m);
// vs
void modifies(T *param);
This case is mostly about style: do you want the code to look like call(obj) or call(&obj)? However, there are two points where the difference matters: the optional case, below, and you want to use a reference when overloading operators.
...and optional
void modifies(T *param=0); // default value optional, too
// vs
void modifies();
void modifies(T ¶m);
Parameter not modified
void uses(T const ¶m);
// vs
void uses(T param);
This is the interesting case. The rule of thumb is "cheap to copy" types are passed by value — these are generally small types (but not always) — while others are passed by const ref. However, if you need to make a copy within your function regardless, you should pass by value. (Yes, this exposes a bit of implementation detail. C'est le C++.)
...and optional
void uses(T const *param=0); // default value optional, too
// vs
void uses();
void uses(T const ¶m); // or optional(T param)
There's the least difference here between all situations, so choose whichever makes your life easiest.
Const by value is an implementation detail
void f(T);
void f(T const);
These declarations are actually the exact same function! When passing by value, const is purely an implementation detail. Try it out:
void f(int);
void f(int const) { /* implements above function, not an overload */ }
typedef void NC(int); // typedefing function types
typedef void C(int const);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
Pass by value:
void func (vector v)
Pass variables by value when the function needs complete isolation from the environment i.e. to prevent the function from modifying the original variable as well as to prevent other threads from modifying its value while the function is being executed.
The downside is the CPU cycles and extra memory spent to copy the object.
Pass by const reference:
void func (const vector& v);
This form emulates pass-by-value behavior while removing the copying overhead. The function gets read access to the original object, but cannot modify its value.
The downside is thread safety: any change made to the original object by another thread will show up inside the function while it's still executing.
Pass by non-const reference:
void func (vector& v)
Use this when the function has to write back some value to the variable, which will ultimately get used by the caller.
Just like the const reference case, this is not thread-safe.
Pass by const pointer:
void func (const vector* vp);
Functionally same as pass by const-reference except for the different syntax, plus the fact that the calling function can pass NULL pointer to indicate it has no valid data to pass.
Not thread-safe.
Pass by non-const pointer:
void func (vector* vp);
Similar to non-const reference. The caller typically sets the variable to NULL when the function is not supposed to write back a value. This convention is seen in many glibc APIs. Example:
void func (string* str, /* ... */) {
if (str != NULL) {
*str = some_value; // assign to *str only if it's non-null
}
}
Just like all pass by reference/pointer, not thread-safe.
Since no one mentioned I am adding on it, When you pass a object to a function in c++ the default copy constructor of the object is called if you dont have one which creates a clone of the object and then pass it to the method, so when you change the object values that will reflect on the copy of the object instead of the original object, that is the problem in c++, So if you make all the class attributes to be pointers, then the copy constructors will copy the addresses of the pointer attributes , so when the method invocations on the object which manipulates the values stored in pointer attributes addresses, the changes also reflect in the original object which is passed as a parameter, so this can behave same a Java but dont forget that all your class attributes must be pointers, also you should change the values of pointers, will be much clear with code explanation.
Class CPlusPlusJavaFunctionality {
public:
CPlusPlusJavaFunctionality(){
attribute = new int;
*attribute = value;
}
void setValue(int value){
*attribute = value;
}
void getValue(){
return *attribute;
}
~ CPlusPlusJavaFuncitonality(){
delete(attribute);
}
private:
int *attribute;
}
void changeObjectAttribute(CPlusPlusJavaFunctionality obj, int value){
int* prt = obj.attribute;
*ptr = value;
}
int main(){
CPlusPlusJavaFunctionality obj;
obj.setValue(10);
cout<< obj.getValue(); //output: 10
changeObjectAttribute(obj, 15);
cout<< obj.getValue(); //output: 15
}
But this is not good idea as you will be ending up writing lot of code involving with pointers, which are prone for memory leaks and do not forget to call destructors. And to avoid this c++ have copy constructors where you will create new memory when the objects containing pointers are passed to function arguments which will stop manipulating other objects data, Java does pass by value and value is reference, so it do not require copy constructors.
Do I need to pass pointers, references, or non-pointer and non-reference values?
This is a question that matters when writing a function and choosing the types of the parameters it takes. That choice will affect how the function is called and it depends on a few things.
The simplest option is to pass objects by value. This basically creates a copy of the object in the function, which has many advantages. But sometimes copying is costly, in which case a constant reference, const&, is usually best. And sometimes you need your object to be changed by the function. Then a non-constant reference, &, is needed.
For guidance on the choice of parameter types, see the Functions section of the C++ Core Guidelines, starting with F.15. As a general rule, try to avoid raw pointers, *.
There are three methods of passing an object to a function as a parameter:
Pass by reference
pass by value
adding constant in parameter
Go through the following example:
class Sample
{
public:
int *ptr;
int mVar;
Sample(int i)
{
mVar = 4;
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value of the pointer is " << *ptr << endl
<< "The value of the variable is " << mVar;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
char ch;
cin >> ch;
}
Output:
Say i am in someFunc
The value of the pointer is -17891602
The value of the variable is 4
The following are the ways to pass a arguments/parameters to function in C++.
1. by value.
// passing parameters by value . . .
void foo(int x)
{
x = 6;
}
2. by reference.
// passing parameters by reference . . .
void foo(const int &x) // x is a const reference
{
x = 6;
}
// passing parameters by const reference . . .
void foo(const int &x) // x is a const reference
{
x = 6; // compile error: a const reference cannot have its value changed!
}
3. by object.
class abc
{
display()
{
cout<<"Class abc";
}
}
// pass object by value
void show(abc S)
{
cout<<S.display();
}
// pass object by reference
void show(abc& S)
{
cout<<S.display();
}
This blog post describes a technique for creating a container of heterogeneous pointers. The basic trick is to create a trivial base class (i.e. no explicit function declarations, no data members, nothing) and a templated derived class for storing std::function<> objects with arbitrary signatures, then make the container hold unique_ptrs to objects of the base class. The code is also available on GitHub.
I don't think this code can be made robust; std::function<> can be created from a lambda, which might include a capture, which might include a by-value copy of a nontrivial object whose destructor must be called. When the Func_t type is deleted by unique_ptr upon removal from the map, only its (trivial) destructor will be called, so the std::function<> objects never get properly deleted.
I've replaced the use-case code from the example on GitHub with a "non-trivial type" that is then captured by value inside a lambda and added to the container. In the code below, the parts copied from the example are noted in comments; everything else is mine. There's probably a simpler demonstration of the problem, but I'm struggling a bit to even get a valid compile out of this thing.
#include <map>
#include <memory>
#include <functional>
#include <typeindex>
#include <iostream>
// COPIED FROM https://plus.google.com/+WisolCh/posts/eDZMGb7PN6T
namespace {
// The base type that is stored in the collection.
struct Func_t {};
// The map that stores the callbacks.
using callbacks_t = std::map<std::type_index, std::unique_ptr<Func_t>>;
callbacks_t callbacks;
// The derived type that represents a callback.
template<typename ...A>
struct Cb_t : public Func_t {
using cb = std::function<void(A...)>;
cb callback;
Cb_t(cb p_callback) : callback(p_callback) {}
};
// Wrapper function to call the callback stored at the given index with the
// passed argument.
template<typename ...A>
void call(std::type_index index, A&& ... args)
{
using func_t = Cb_t<A...>;
using cb_t = std::function<void(A...)>;
const Func_t& base = *callbacks[index];
const cb_t& fun = static_cast<const func_t&>(base).callback;
fun(std::forward<A>(args)...);
}
} // end anonymous namespace
// END COPIED CODE
class NontrivialType
{
public:
NontrivialType(void)
{
std::cout << "NontrivialType{void}" << std::endl;
}
NontrivialType(const NontrivialType&)
{
std::cout << "NontrivialType{const NontrivialType&}" << std::endl;
}
NontrivialType(NontrivialType&&)
{
std::cout << "NontrivialType{NontrivialType&&}" << std::endl;
}
~NontrivialType(void)
{
std::cout << "Calling the destructor for a NontrivialType!" << std::endl;
}
void printSomething(void) const
{
std::cout << "Calling NontrivialType::printSomething()!" << std::endl;
}
};
// COPIED WITH MODIFICATIONS
int main()
{
// Define our functions.
using func1 = Cb_t<>;
NontrivialType nt;
std::unique_ptr<func1> f1 = std::make_unique<func1>(
[nt](void)
{
nt.printSomething();
}
);
// Add to the map.
std::type_index index1(typeid(f1));
callbacks.insert(callbacks_t::value_type(index1, std::move(f1)));
// Call the callbacks.
call(index1);
return 0;
}
This produces the following output (using G++ 5.1 with no optimization):
NontrivialType{void}
NontrivialType{const NontrivialType&}
NontrivialType{NontrivialType&&}
NontrivialType{NontrivialType&&}
NontrivialType{const NontrivialType&}
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling NontrivialType::printSomething()!
Calling the destructor for a NontrivialType!
I count five constructor calls and four destructor calls. I think that indicates that my analysis is correct--the container cannot properly destroy the instance it owns.
Is this approach salvageable? When I add a virtual =default destructor to Func_t, I see a matching number of ctor/dtor calls:
NontrivialType{void}
NontrivialType{const NontrivialType&}
NontrivialType{NontrivialType&&}
NontrivialType{NontrivialType&&}
NontrivialType{const NontrivialType&}
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling NontrivialType::printSomething()!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
... so I think this change might be sufficient. Is it?
(Note: the correctness--or lack thereof--of this approach is independent of whether the idea of a container of heterogeneous functions is a good idea. In a few very specific cases, there may be some merit, for instance, when designing an interpreter; e.g., a Python class may be thought of as just such a container of heterogeneous functions plus a container of heterogeneous data types. But in general, my decision to ask this question does not indicate that I think this is likely to be a good idea in very many cases.)
This is basically someone trying to implement type erasure and getting it horribly wrong.
Yes, you need a virtual destructor. The dynamic type of the thing being deleted is obviously not Func_t, so it's plainly UB if the destructor isn't virtual.
The whole design is completely broken, anyway.
The point of type erasure is that you have a bunch of different types that share a common characteristic (e.g. "can be called with an int and get a double back"), and you want to make them into a single type that has that characteristic (e.g., std::function<double(int)>). By its nature, type erasure is a one-way street: once you have erased the type, you can't get it back without knowing what it is.
What does erasing something down to an empty class mean? Nothing, other than "it's a thing". It's a std::add_pointer_t<std::common_type_t<std::enable_if_t<true>, std::void_t<int>>> (more commonly known as void*), obfuscated in template clothing.
There are plenty of other problems with the design. Because the type was erased into nothingness, it had to recover the original type in order to do anything useful with it. But you can't recover the original type without knowing what it is, so it ends up using the type of arguments passed to Call to infer the type of the thing stored in the map. That is ridiculously error-prone, because A..., which represents the types and value categories of the arguments passed to Call, is highly unlikely to match exactly the parameter types of std::function's template argument. For instance, if you have a std::function<void(int)> stored in there, and you tried to call it with a int x = 0; Call(/* ... */ , x);, it's undefined behavior. Go figure.
To make it worse, any mismatch is hidden behind a static_cast that causes undefined behavior, making it harder to find and fix. There's also the curious design that requires the user to pass a type_index, when you "know" what the type is anyway, but it's just a sideshow when compared to all the other problems with this code.
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.