I am reading this tutorial about function pointers which said that function pointers can replace a switch statement
http://www.newty.de/fpt/intro.html .
Can anyone clarify?
We have a switch statement like this:
// The four arithmetic operations ... one of these functions is selected
// at runtime with a swicth or a function pointer
float Plus (float a, float b) { return a+b; }
float Minus (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide (float a, float b) { return a/b; }
// Solution with a switch-statement - <opCode> specifies which operation to execute
void Switch(float a, float b, char opCode)
{
float result;
// execute operation
switch(opCode)
{
case '+' : result = Plus (a, b); break;
case '-' : result = Minus (a, b); break;
case '*' : result = Multiply (a, b); break;
case '/' : result = Divide (a, b); break;
}
cout << "Switch: 2+5=" << result << endl; // display result
}
// Solution with a function pointer - <pt2Func> is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// "specifies" which operation shall be executed.
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
float result = pt2Func(a, b); // call using function pointer
cout << "Switch replaced by function pointer: 2-5="; // display result
cout << result << endl;
}
// Execute example code
void Replace_A_Switch()
{
cout << endl << "Executing function 'Replace_A_Switch'" << endl;
Switch(2, 5, /* '+' specifies function 'Plus' to be executed */ '+');
Switch_With_Function_Pointer(2, 5, /* pointer to function 'Minus' */ &Minus);
}
As you can see, the Replace_A_Switch() function as an example is very unclear. Supposed we need to point the function pointer to one of 4 arithmetic functions(Plus,Mins,Multiply,Divide). how can we know which one we need to point to? We have to use the switch statement again to point the function pointer to the arithmetic functions , right?
It will be like this one**(please the comment in the code)**:
void Replace_A_Switch()
{
.....................
..........
//How can we know this will point to the &Minus function if we don't use the switch statement outside?
Switch_With_Function_Pointer(2, 5, /* pointer to function 'Minus' */ &Minus);
}
So in summary, what is the advantages of function pointer, it always said that the function pointer a late-binding mechanism , but in this tutorial i dont see any advantage of the function pointer for late binding.
Any help are very appreciated. Thanks.
What you're saying is pretty well true, you still need to decide somewhere what function pointer to use.
What you're looking at though is a pretty simple, contrived example for explanation purpose. It shows how you can leverage a function pointer. In this case it might be pointlessly complicated but a real case would probably be too complicated to use to instruct in this basic concept.
The difference becomes much clearer when you've got a lot of functions that have the same switch, or a switch with subsets of the same set. The difference is all the same though (this is also important). In that case, why rewrite it a bunch of times?
It also opens your code for a change in how the decision is made. Maybe you want to invert '+' and '-' for whatever reason. Change the point where you make the pointer and all the client code catches up.
Finally, what if you don't even need to make the decision? Instead of replacing the switch for example, what if you just wanted to do the addition version? Obviously addition is too simple a task for this level of design, but again it's just an example.
All this is true whether you're using function pointers or a class hierarchy. Someone has to decide what the input will be. What these constructs do is provide you a method to compose different bits into a running program. It also separates the part that is responsible for deciding which version of things to use from the using of those things. There are a lot of different ways to approach that creation (see creational design patterns for some).
As the tutorial states there are no advantages and the basic calculator is simply an example. The main use of function pointers is to allow the API-dev to define a function, which does something that is not known at the time the API is created.
A better example is probably qsort, which takes a comparison function. Thanks to this function-pointer argument it is possible to implement the sort in a generic way. Since you could not possibly know what kind of data needs to be sorted you can't know how the <,=,> operators have to be implemented. Thus you expect the caller to provide a function that implements the comparison thereby avoiding this dilemma.
In general, function pointers are often useful if you want to program something in a generic way. Its use is that of function-arguments in other languages. If someone asked you to implement a simple reduce function for example, you could come up with something like this:
void reduce(void *data, size_t nmemb, size_t size,
void (*op)(void *, void *), void *res){
int i;
for (i = 0; i < nmemb; ++i){
op(data, res);
data = (void *)((unsigned char*)data + size);
}
}
Clearly it is very advantageous over rewriting this for operations like multiply, add, and more complex ones all over again with the respective function replacing op.
I can see how you can convert your '+', '-' etc into an enum, and store the 4 func pointers into an array ordered by the enum order. After that arr[op] is the function you want, just execute that.
Alternatively a std::map<String, FuncType> map from + -> &Plus.
as from what i see..
the pt2Func is a name defined for pointer which references a function
you can see how it works in the main where it is being called
(removed the comment to make it more readable)
Switch_With_Function_Pointer(2, 5, &Minus);
&Minus here is a pointer that references to your function Minus
this is stupid as you are calling a function to reference another function by using a pointer.
There is no benefit and it does nothing special.. its just another more complicated way to call the Minus function
the Switch function however is just a normal switch encapsulated in a function for reusability
Related
I've seen this used by other people and it looks really clever, but I'm not sure if it's good or bad practice. It works, and I like the way it works, personally, but is doing this actually useful in the scope of a larger program?
What they've done is dynamically allocate some data type inside the actual function argument, and delete it in the function. Here's an example:
#include <iostream>
class Foo {
private:
int number;
public:
Foo(int n) : number(n) { }
int num() { return number; }
Foo* new_num (int i) { number = i; }
};
void some_func (int thing, Foo* foo);
int main() {
std::cout << "Enter number: ";
int n;
std::cin >> n;
some_func(n, new Foo(0)); // <-- uses the 'new' operator with a function argument
return 0;
}
// calculates difference between 'thing' and 'n'
// then puts it inside the Foo object
void some_func (int thing, Foo* foo) {
std::cout << "Enter another number: ";
int n;
std::cin >> n;
std::cout << "Difference equals " << foo->new_num(thing - n)->num() << std::endl;
delete foo; // <-- the Foo object is deleted here
}
I knew that it was possible to use operators in function arguments, but I was only aware of doing this with the operators on levels 2, 4 through 15, and 17, as well as the assignment operators, ? :, ++ and --, unary + and -, !, ~, * and &, sizeof and casts. Stuff like this:
foo((x < 3)? 5 : 6, --y * 7);
bar(player->weapon().decr_durability().charge(0.1), &shield_layers);
So, I actually have two questions.
Is the new-as-an-argument good practice?
Since apparently any operator returning a type works if new works, are using these good practice?
::, new [], throw, sizeof..., typeid, noexcept, alignof
No, this is not clever at all. It takes a function that could be simpler and more general and reduces its capabilities for no reason, while at the same time creating an entry point into your program for difficult-to-debug bugs.
It's not clear to me exactly what Foo::new_num is meant to do (right now it doesn't compile), so I won't address your example directly, but consider the following two code samples:
void bad_function(int i, F * f)
{
f->doSomething(i);
delete f;
}
// ...
bad_function(0, new F(1, 2, 3));
versus
void good_function(int i, F & f)
{
f.doSomething(i);
}
// ...
good_function(0, F(1, 2, 3));
In both cases you allocate a new F object as part of the method call and it's destroyed once you're done using it, so you get no advantage by using bad_function instead of good function. However there's a bunch of stuff you can do with good_function that's not so easy to do with bad_function, e.g.
void multi_function(const std::vector<int> & v, F & f)
{
for(int i : v) { good_function(i, f); }
}
Using the good_function version means you're also prevented by the language itself from doing various things you don't want to do, e.g.
F * f; // never initialized
bad_function(0, f); // undefined behavior, resulting in a segfault if you're lucky
It's also just better software engineering, because it makes it a lot easier for people to guess what your function does from its signature. If I call a function whose purpose involves reading in a number from the console and doing arithmetic, I absolutely do not expect it to delete the arguments I pass in, and after I spent half an hour figuring out what's causing some obscure crash in some unrelated part of the code I'm going to be furious with whoever wrote that function.
By the way, assuming that F::doSomething doesn't alter the value of the current instance of F in any way, it should be declared const:
class F
{
void doSomething(int i) const;
// ...
};
and good_function should also take a const argument:
void good_function(int i, const F & f);
This lets anyone looking at the signature confidently deduce that the function won't do anything stupid like mess up the value of f that's passed into the function, because the compiler will prevent it. And that in turn lets them write code more quickly, because it means there's one less thing to worry about.
In fact if I see a function with a signature like bad_function's and there's not an obvious reason for it, then I'd immediately be worried that it's going to do something I don't want and I'd probably read the function before using it.
I need to use participants a[quantity] in the function dataIn. I tried making
void dataIn(int quantity, participants a[quantity]);
but that didnt work. Btw quantity is being taken from a text file.
void dataIn(int quantity);
int main()
{
ifstream in("duomenys.txt");
int quantity;
in >> quantity;
participants a[quantity];
dataIn(quantity);
return 0;
}
The signature of your function is
void dataIn(int quantity, participants a[quantity])
At very first, C++ doesn't allow to use function parameters outside the function body, so this is the reason why it won't compile.
Apart from, this signature actually is equivalent to
void dataIn(int quantity, participants*)
// legal variant of, exactly equivalent(!),
// not re-using quantity parameter either (-> compiles):
void dataIn(int quantity, participants[])
Raw arrays are always passed to functions as pointer to their first element, we say: an array decays to a pointer. Note, though, that this doesn't apply for further dimensions, i. e.
void f(int[whatever][SomeCompileTimeConstant])
remains equivalent to
void f(int(*)[SomeCompileTimeConstant])
Back to the original function: Note that it accepts two parameters, so you need to pass two as well:
participants a[quantity];
dataIn(quantity, a);
// ^
Note the array decaying to pointer, as mentioned already!
Additionally be aware that above is invalid C++:
int main()
{
participants a[quantity];
}
You are defining a VLA (variable length array), but that is only valid in C, not in C++. However, as many C++ compilers can translate C as well, they provide VLA for C++ as an extension. And that's the problem, no guarantee that all compilers do so, so your code is not portable.
So if you need dynamically sized arrays, switch over to std::vector*:
void dataIn(size_t quantity, std::vector<participant>& v)`
Note that I changed type of quantity parameter as well: Appropriate type for passing array lengths is size_t, not int.
std::vector<participant> a;
a.reserve(quantity); // optimisation: prevents re-allocations
dataIn(quantity, participants);
Actually, with std::vector you can have a much cleaner interface:
std::vector<participant> dataIn( )
// ^ no parameters needed at all!
{
ifstream in("...");
size_t quantity;
in >> quantity;
// TODO: check stream state, and possibly maximum for quantity (file validity!)
std::vector<participant> a;
a.reserve(quantity);
while(quantity--) { ... }
return a;
}
As you see, all relevant file operations now are placed into one single function (dataIn) and not distributed all over your programme. Especially, the file stream itself is in scope of this function as well and will be closed automatically on leaving. Be aware that with return value optimisation, the vector will be immediately constructed at the target location, so there even isn't any copying or moving involved...
* Even if you need fixed size arrays, std::array is a more modern and better alternative, it just wraps around a raw array, but behaves like any other ordinary object, so nothing of all that decaying to pointer stuff, additionally it comes with a more elaborate interface, e. g. a size() member, so no need to rely on the 'good old' sizeof(array)/sizeof(*array) trick either.
You can't just access a function parameter like that.
In the "participants a[quantity]", the compiler don't know about "quantity".
So the "quantity" variable must be known.
Like :
void dataIn(int quantity, participants a[15]);
If you don't know the size, send it as a pointer.
void dataIn(int quantity, participants *a);
And parse it thanks to the "quantity" variable.
void dataIn(int quantity, participants *a)
{
for (int i = 0; i < quantity; i++) {
//Do something with the array of struct...
}
}
I am new to C++ and have done only MATLAB earlier.
My Q is about the input argument of the following functions, which call variables by value,reference and pointer.
void SwapbyValue (int a, int b){
// Usual swapping code
}
void SwapbyRef (int &a, int &b){
// Usual swapping code
}
void SwapbyPoint(int *a,int *b){
//Usual swapping code
}
Since my Q isn't about how the above functions work but rather about how I call them, I've left out the code. So, I understand we call the above functions by typing SwapbyRef (i1,i2),SwapbyRef (i1,i2) and SwapbyPoint(&i1,&i2) when i1 and 12 are int.
That confuses me the life out of me. Okay, I get that the first function takes in values and makes sense. But in the second one, calling by just i1 and i2 doesn't make sense as when the function is defined, we set its input as &a and not just a but it still runs. Again in the third, we set the input argument as a pointer i.e. *a but we're passing an address &a (like 0x7956a69314d8) when we call it.
Why does it run when we pass the wrong kind of input to the function?
For example,a Matlab analogy,it looks like passing a char to a int function. Help!
int &a is a reference to an int, meaning, it will accept all int variables that already exist. What you cannot do is for example SwapbyRef(4, 5) using SwapbyRef (int &a, int &b), because 4 and 5 are temporary ints that do not exist somewhere in memory as variables.
Btw, you should probably just look up what a reference in c++ is. That would help you most, I think.
My actual question is it really possible to compare values contained in two void pointers, when you actually know that these values are the same type? For example int.
void compVoids(void *firstVal, void *secondVal){
if (firstVal < secondVal){
cout << "This will not make any sense as this will compare addresses, not values" << endl;
}
}
Actually I need to compare two void pointer values, while outside the function it is known that the type is int. I do not want to use comparison of int inside the function.
So this will not work for me as well: if (*(int*)firstVal > *(int*)secondVal)
Any suggestions?
Thank you very much for help!
In order to compare the data pointed to by a void*, you must know what the type is. If you know what the type is, there is no need for a void*. If you want to write a function that can be used for multiple types, you use templates:
template<typename T>
bool compare(const T& firstVal, const T& secondVal)
{
if (firstVal < secondVal)
{
// do something
}
return something;
}
To illustrate why attempting to compare void pointers blind is not feasible:
bool compare(void* firstVal, void* secondVal)
{
if (*firstVal < *secondVal) // ERROR: cannot dereference a void*
{
// do something
}
return something;
}
So, you need to know the size to compare, which means you either need to pass in a std::size_t parameter, or you need to know the type (and really, in order to pass in the std::size_t parameter, you have to know the type):
bool compare(void* firstVal, void* secondVal, std::size_t size)
{
if (0 > memcmp(firstVal, secondVal, size))
{
// do something
}
return something;
}
int a = 5;
int b = 6;
bool test = compare(&a, &b, sizeof(int)); // you know the type!
This was required in C as templates did not exist. C++ has templates, which make this type of function declaration unnecessary and inferior (templates allow for enforcement of type safety - void pointers do not, as I'll show below).
The problem comes in when you do something (silly) like this:
int a = 5;
short b = 6;
bool test = compare(&a, &b, sizeof(int)); // DOH! this will try to compare memory outside the bounds of the size of b
bool test = compare(&a, &b, sizeof(short)); // DOH! This will compare the first part of a with b. Endianess will be an issue.
As you can see, by doing this, you lose all type safety and have a whole host of other issues you have to deal with.
It is definitely possible, but since they are void pointers you must specify how much data is to be compared and how.
The memcmp function may be what you are looking for. It takes two void pointers and an argument for the number of bytes to be compared and returns a comparison. Some comparisons, however, are not contingent upon all of the data being equal. For example: comparing the direction of two vectors ignoring their length.
This question doesn't have a definite answer unless you specify how you want to compare the data.
You need to dereference them and cast, with
if (*(int*) firstVal < *(int*) secondVal)
Why do you not want to use the int comparison inside the function, if you know that the two values will be int and that you want to compare the int values that they're pointing to?
You mentioned a comparison function for comparing data on inserts; for a comparison function, I recommend this:
int
compareIntValues (void *first, void *second)
{
return (*(int*) first - *(int*) second);
}
It follows the convention of negative if the first is smaller, 0 if they're equal, positive if the first is larger. Simply call this function when you want to compare the int data.
yes. and in fact your code is correct if the type is unsigned int. casting int values to void pointer is often used even not recommended.
Also you could cast the pointers but you have to cast them directly to the int type:
if ((int)firstVal < (int)secondVal)
Note: no * at all.
You may have address model issues doing this though if you build 32 and 64 bits. Check the intptr_t type that you could use to avoid that.
if ((intptr_t)firstVal < (intptr_t)secondVal)
int add (int x, int y=1)
int main ()
{
int result1 = add(5);
int result2 = add(5, 3);
result 0;
}
VS
int add (int x, int y)
int main ()
{
int result1 = add(5, 1);
int result2 = add(5, 3);
result 0;
}
What is the advantage of using the default function parameter, in term of execution speed, memory usage and etc? For beginner like me, I sometimes got confused before I realized this usage of default function parameter; isn't it coding without default function parameter made the codes easier to read?
Your add function is not a good example of how to use defaulted parameters, and you are correct that with one it is harder to read.
However, this not true for all functions. Consider std::vector::resize, which looks something like:
template<class T>
struct vector_imitation {
void resize(int new_size, T new_values=T());
};
Here, resizing without providing a value uses T(). This is a very common case, and I believe almost everyone finds the one-parameter call of resize easy enough to understand:
vector_imitation<int> v; // [] (v is empty)
v.resize(3); // [0, 0, 0] (since int() == 0)
v.resize(5, 42); // [0, 0, 0, 42, 42]
The new_value parameter is constructed even if it is never needed: when resizing to a smaller size. Thus for some functions, overloads are better than defaulted parameters. (I would include vector::resize in this category.) For example, std::getline works this way, though it has no other choice as the "default" value for the third parameter is computed from the first parameter. Something like:
template<class Stream, class String, class Delim>
Stream& getline_imitation(Stream &in, String &out, Delim delim);
template<class Stream, class String>
Stream& getline_imitation(Stream &in, String &out) {
return getline_imitation(in, out, in.widen('\n'));
}
Defaulted parameters would be more useful if you could supply named parameters to functions, but C++ doesn't make this easy. If you have encountered defaulted parameters in other languages, you'll need to keep this C++ limitation in mind. For example, imagine a function:
void f(int a=1, int b=2);
You can only use the given default value for a parameter if you also use given defaults for all later parameters, instead of being able to call, for example:
f(b=42) // hypothetical equivalent to f(a=1, b=42), but not valid C++
If there is a default value that will provide correct behavior a large amount of the time then it saves you writing code that constantly passes in the same value. It just makes things more simple than writing foo(SOME_DEFAULT) all over the place.
It has a wide variety of uses. I usually use them in class constructors:
class Container
{
// ...
public:
Container(const unsigned int InitialSize = 0)
{
// ...
}
};
This lets the user of the class do both this:
Container MyContainer; // For clarity.
And this:
Container MyContainer(10); // For functionality.
Like everything else it depends.
You can use it to make the code clearer.
void doSomething(int timeout=10)
{
// do some task with a timeout, if not specified use a reasonable default
}
Is better than having lots of magic values doSomething(10) throughout your code
But be careful using it where you should really do function overloading.
int add(int a)
{
return a+1;
}
int add(int a,int b)
{
return a+b;
}
As Ed Swangren mentioned, some functions have such parameters that tend to have the same value in most calls. In these cases this value can be specified as default value. It also helps you see the "suggested" value for this parameter.
Other case when it's useful is refractoring, when you add some functionality and a parameter for it to a function, and don't want to break the old code. For example, strlen(const char* s) computes the distance to the first \0 character in a string. You could need to look for another characted, so that you'll write a more generic version: strlen(const char* s, char c='\0'). This will reuse the code of your old strlen without breaking compatibility with old code.
The main problem of default values is that when you review or use code written by others, you may not notice this hidden parameter, so you won't know that the function is more powerful than you can see from the code.
Also, google's coding style suggests avoiding them.
A default parameter is a function parameter that has a default value provided to it. If the user does not supply a value for this parameter, the default value will be
used. If the user does supply a value for the default parameter, the user-supplied value is used.
In computer programming, a default argument is an argument to a function that a programmer is not required to specify. In most programming languages, functions may take one or more arguments. Usually, each argument must be specified in full (this is the case in the C programming language)
Advantages of using default parameter, as others have pointed out, is indeed the "clarity" it brings in the code with respect to say function overloading.
But, it is important to keep in mind the major disadvantage of using this compile-time feature of the language: the binary compatibility and default function parameter does not go hand in hand.
For this reason, it is always good to avoid using default params in your API/interfaces classes. Because, each time you change the default param to something else, your clients will need to be recompiled as well as relinked.
Symbian has some very good C++ design patterns to avoid such BC.
Default parameters are better to be avoided.
let's consider the below example
int DoThis(int a, int b = 5, int c = 6) {}
Now lets say you are using this in multiple places
Place 1: DoThis(1);
Place 2: DoThis(1,2);
Place 3: DoThis(1,2,3);
Now you wanted to add 1 more parameter to the function and it is a mandatory field (extended feature for that function).
int DoThis(int a, int x, int b =5, int c=6)
Your compiler throws error for only "Place 1". You fix that. What about other others?
Imagine what happens in a large project? It would become a nightmare to identify it's usages and updating it rightly.
Always overload:
int DoThis(int a) {}
int DoThis(int a, int b {}
int DoThis(int a, int b, int c) {}
int DoThis(int a, int b, int c, int x) {}