For example, if I have the following:
void foo(string* s)
{
bar(s); // this line fails to compile, invalid init. error
}
void bar(const string& cs)
{
// stuff happens here
}
What conversions do I need to make to have the call the bar succeed?
Change it to:
bar(*s);
void foo(string* s)
{
bar(*s);
}
s points to a string, and bar requires a (reference to a) string, so you need to give bar what s points to. The way you spell "what s points to" is *s.
When converting a pointer to a reference it is important to make sure that you are not trying to convert a NULL pointer. The compiler has to allow you to do the conversion (because in general it can't tell if it is a valid reference).
void foo(string* s)
{
if(0 != s){
bar(*s);
}
}
The * operator is the inverse of the & operator. To convert from a reference to a pointer your use & (address of). To convert a pointer to a reference use * (contents of).
Related
I though that I understood iterators and addressing etc. but obviously not. See my below code below which is purely an example.
I need to be able to pass by pointer or reference each structure of mystructs to MyFunc(). The function should be able to update the actual structure that is passed, and not by copy or value.
I receive the compiler error :
error: cannot convert 'MY_STRUCT' to 'MY_STRUCT*' for argument '1' to 'void MyFunc(MY_STRUCT*)'
If I just pass the iterator address, this also doesn't work.
What is the correct way to do this. Thanks in advance.
typedef struct
{
int var1;
int var2;
std::string name;
}MY_STRUCT;
std::list<MY_STRUCT> mystructs;
void MyFunc(MY_STRUCT*)
{
// Do something
}
// populate the list with structs etc.. not included here
//.....
for (std::list<MY_STRUCT>::iterator it = mystructs.begin();it != mystructs.end(); ++it)
{
MyFunc(*it);
}
Passing by reference in C++ is done with:
void MyFunc(MY_STRUCT&)
{
// Do something
}
So your call would be correct, what you currently want is to pass the pointer, which you can do with dereferencing the dereferenced iterator (by passing the address of the dereferenced object):
void MyFunc(MY_STRUCT*)
{
// Do something
}
// populate the list with structs etc.. not included here
//.....
int main() {
for (std::list<MY_STRUCT>::iterator it = mystructs.begin();it != mystructs.begin(); ++it)
{
MyFunc(&*it);
}
}
Your function requires a pointer, use & to get the address of something.
MyFunc(&*it);
*it returns a reference to the MY_STRUCT object, you need to use & to convert that reference to a pointer. This is normal, the fact that you are using iterators makes no difference at all.
The alternative (maybe better in C++) would be to convert your MyFunc function to take a reference instead of a pointer.
Can anyone explain to me why the following segment compiles but the commented line after doesn't?
struct tObj
{
int data;
int moreData;
}
...
void funcToCall (tObj *obj, int moreData)
{
//Useful stuff here
}
void mainFunction ()
{
vector<tObj>::iterator it = vectorOfObjects.begin(); //assumes vectorOfObjects is already defined
while (it != vectorOfObjects.end())
{
funcToCall (&(*it), 0); //This line works
funcToCall (it, 0); //This line produces an error
it++;
}
}
The error produced is this:
error: cannot convert ‘std::vector<tObj>::iterator {aka __gnu_cxx::__normal_iterator<tObj*, std::vector<tObj> >}’ to ‘tObj*’
Any ideas on why &(*it) works but just plain it doesn't? Logically they are the same, aren't they?
Because doesn't * mean to dereference and & mean pass by reference aka cancelling each other out?
it is an iterator object, passing it as-is would mean you're trying to pass an object of type vector<tObj>::iterator for a function expecting tObj*, and thus the error.
When you do *it you'd get the underlying object the iterator is representing and when you apply & atop that, you get that object's address, which is of type tObj* which agrees with the function's argument type and thus no error.
That the code would be compiled you have to declare an overloaded function like
void funcToCall ( std::vector<tObj>::iterator it, int moreData)
{
//Useful stuff here
}
In general case types tObj * and vector<tObj>::iterator are different types though in some old realizations of std::vector its iterator is indeed defined as a pointer..
For the following code snippets why would I use one assignment vs another? thx
void addOne(int &x)
{
x +=1;
}
void (*inc)(int &x) = addOne; // what is the purpose of doing "addOne"
void (*inc)(int &x) = &addOne; // vs &addOne ??
int a = 10;
inc(a);
The purpose of one over the other is C compatibility. C said that functions will decay to pointers-to-functions automatically. To be compatible, C++ had to do the same.
Note that when C++ introduced a new function pointer type (member function pointers), they do not decay automatically. So if the C++ committee had their way, odds are good you'd need that & there.
Brevity, style. It's the same with using * when calling them.
Also note array vs &array[0].
From the book C++ Programming Languauge, it is cleary indicated that & and * operators are optional for pointers to functions:
There are only two things one can do to a function: call it and take
its address. The pointer obtained by taking the address of a function
can then be used to call the function. For example:
void error (string s) { /* ... */ }
void (*efct )(string ); // pointer to function
void f ()
{
efct = &error ; // efct points to error
efct ("error "); // call error through efct
}
The compiler will discover that efct is a pointer and call the
function pointed to. That is, dereferencing of a pointer to function
using * is optional. Similarly, using & to get the address of a
function is optional:
void (*f1 )(string ) = &error ; // ok
void (*f2 )(string ) = error ; // also ok; same meaning as &error
void g ()
{
f1 ("Vasa"); // ok
(*f1 )("Mary Rose"); // also ok
}
As others pointed out, pointer to member function is new/different in C++. The & is not optional to point a member and it is explained as (in C++ Programming Languauge Book):
A pointer to member can be obtained by applying the address-of
operator & to a fully qualified class member name, for example,
&Std_interface::suspend.
A function is already a pointer; therefore, you do not need the address operator.
I'm new to this and now sure whether this is doable. I want to add a argument of std::set<std::string> to a function, and set its default value to be NULL, to avoid impact on previous uses.
So basically,
func(int a); turns into
func(int a, std::set<std::string> & temp = NULL);
but this will give me an error "error C2440: 'default argument' : cannot convert from 'int' to 'std::set<_Kty> &'"
Can anybody help me on this?
Thanks
In order to set the default to NULL, you'd have to be passing an std::set<std::string>*, not a reference to a value type.
Furthermore, if you are passing a non-pointer type and you want to assign any default value at all, it has to be a const reference, because you can't (advisably!) assign a temporary to it otherwise.
So your choices for "default" values are basically:
std::set<std::string>* = NULL
or:
const std::set<std::string>& = std::set<std::string>()
or option 3, using function overloading more directly:
void myfunction() {dothing(0);}
void myfunction(std::set<std::string>& optional_param)
{ dothing(optional_param.size()); }
or option 4, having a corresponding bool indicating whether parameter is "set":
void myfunction(std::set<std::string>& param, bool param_has_meaning=true) {}
It looks like you're already on the track to the third option. You just need to write two definitions, one with and one without the parameter.
You have the right idea - using a reference. However, a reference cannot be NULL by default, like a pointer can. Therefore, what you probably want to do is overload the function so that you use void func(int a) when you don't want to pass a set as a parameter and use void func( int a, std::set<std::string>& temp)
This way, you can actually provide two separate implementations - one that works on a set and one that doesn't. From a usage point of view, it would have the same effect as a default parameter. From a coding point of view, each implementation would have a clearer purpose.
If you're not going to be modifying the set, might I suggest using a const reference instead:
void func( int a, const std::set<std::string>& temp )
You can't have a NULL reference in C++.
The simplest way would be to have a dummy empty set:
std::set<std::string> empty;
void func(int a, std::set<std::string>& temp = empty)
{
// ...
}
You can then call:
func(1);
Neater, still, would be to use function overloading to create a wrapper so that you have no need to default:
void func(int a, std::set<std::string>& temp)
{
}
void func(int a)
{
std::set<std::string> empty;
func(a, empty);
}
// And then...
func(1);
All this assumes that if you pass in a set you're going to modify it somehow. It's not clear from your question what your intention is but I've made the assumption on the basis that your reference is non-const. If I've miscalculated, then the answer is even simpler:
void func(int a, const std::set<std::string>& temp = std::set<std::string>())
{
}
The following will give you an empty set object:
std::set<std::string>()
I would like to pass a pointer by reference to a function, such that i can actually change the address the passed pointer is pointing to and i'd like to assign this argument a default value.
something like this:
in the declaration
void myFunc(SomeType* &var=NULL);
and the definition:
void MyClass::myFunc(SomeType* &var){
if(var!=NULL)
(*var)=(*someOtherPointer);
if(someCondition)
var=NULL;
}
such that a callee can decide whether he wants to call the function with one argument or without argument. And sucht that if he decides to pass an argument, and someCondition holds, the passed pointer will point to NULL afterwards
however - if i try to do it like this i get a:
Error C2440: 'default argument': 'int' cannot be conveted to 'SomeType *&'
Thanks for the help!
NULL is not an lvalue - it cannot be passed by reference. It would be like passing 4 to a function that expects an int&.
The 'int' part is because NULL is a macro - defined 0.
Your best bet would be using a pointer to pass the pointer by reference, i.e. a double pointer. Then, if the parameter is NULL, nothing was passed. If not, it's the address of the pointer that should be modified [to point to NULL if someCondition holds].
The error message says it all: you are passing an integer instead of a reference-to-a-pointer-to-SomeType. To do what you want, you can use a pointer-to-a-pointer-to-SomeType:
void myFunc(SomeType** var=NULL);
void MyClass::myFunc(SomeType** var){
if(var!=NULL && *var!=NULL)
(**var)=(*someOtherPointer);
if(var!=NULL && someCondition)
*var=NULL;
}
You can also consider using boost::optional (not the simplest code you can use, but the option is there):
void f( boost::optional<int&> r = boost::optional<int&>() )
{
if ( r ) *r = 5;
}
int main()
{
int x = 0;
f( x ); std::cout << x << std::endl; // 5, it did change the value
f(); // compiler will default to an empty optional<int&> object
}
Ok, I can see why you'd do this from the perspective of exercising the C++ brain, but would you really do that in production code? It looks like an incredibly misty technique with side effects, when looking at the code as a colleague 1 year later. Did you think of using two separate functions with clear names, one returning a pointer and one doing any other needed work?
Why not just overload the function?
void myFunc() {
//whatever logic should happen if a null pointer is passed in
}
void myFunc(SomeType* &var) {
if(var!=NULL) {
(*var)=(*someOtherPointer);
}
if(someCondition) {
var=NULL;
}
}