const foo * and const foo &

R

Ralf Goertz

Hi,

I am desperate. I have a huge program using boost::python which crashes
when called from python but which runs fine, when called via main().
While trying to find the problem I encountered an even weirder problem.
Then I tried to write a short program that exhibits the problem, but
that problem vanishes, i.e. the short program behaves as expected but
the big one doesn't. Here is the short one:

#include <iostream>
#include <vector>

using namespace std;

struct foo;

struct Bar {
void bar(const foo &) {
}
};

vector<vector<const foo*> >v;

struct foo { };


int main() {
foo f;
Bar b;
v.push_back(vector<const foo * >(1,&f));
b.bar(*v.back().back()); // (*)
return 0;
}

This compiles. But when I omit the dereferencing in the marked line the
compiler complains (as it should):

error: no matching function for call to 'Bar::bar(const foo*&)'

The problem is: in the big program I do exactly the same. But here the
program compiles *whether* *or* *not* I dereference. How can that be?
The (main()-called) program crashes when compiled without dereferencing
and works fine otherwise. The python called version crashes in both
cases. Every crash happens after the program has already stepped over
the marked line without problem and without producing wrong results.

I am puzzled. What's going on?
 
V

Victor Bazarov

I am desperate. I have a huge program using boost::python which crashes
when called from python but which runs fine, when called via main().
While trying to find the problem I encountered an even weirder problem.
Then I tried to write a short program that exhibits the problem, but
that problem vanishes, i.e. the short program behaves as expected but
the big one doesn't. Here is the short one:

#include<iostream>
#include<vector>

using namespace std;

struct foo;

struct Bar {
void bar(const foo&) {
}
};

vector<vector<const foo*> >v;

struct foo { };


int main() {
foo f;
Bar b;
v.push_back(vector<const foo *>(1,&f));
b.bar(*v.back().back()); // (*)
return 0;
}

This compiles. But when I omit the dereferencing in the marked line the
compiler complains (as it should):

error: no matching function for call to 'Bar::bar(const foo*&)'

The problem is: in the big program I do exactly the same. But here the
program compiles *whether* *or* *not* I dereference. How can that be?

It could be that your 'bar' function is a template there. Or that there
are two of them, one for references to const, and one for pointers (i.e.
they are overloaded). Or it could be something else entirely, and there
is no sense in guessing. Post the code. At least the relevant parts.
Start by removing what's irrelevant. After each removal try running and
see if it still crashes. If it doesn't stop crashing after you've
removed all irrelevant parts, you got the code to post; post it. If it
stops crashing somewhere, you found another reason for it to crash;
investigate.
The (main()-called) program crashes when compiled without dereferencing
and works fine otherwise.

> The python called version crashes in both
cases. Every crash happens after the program has already stepped over
the marked line without problem and without producing wrong results.

I am puzzled. What's going on?

Something is definitely afoot. Fishy. No way to tell what it is until
you post the code that doesn't work.

V
 
U

Ulrich Eckhardt

Ralf said:
struct foo;

struct Bar {
void bar(const foo &) {
}
};

vector<vector<const foo*> >v;

This may seem trivial to manage in small programs, but in larger programs
it is easy to lose track of who owns the objects pointed to here. Using
smart pointers helps. Not using dynamically allocated objects helps, too,
but might create different problems.
int main() {
foo f;
Bar b;
v.push_back(vector<const foo * >(1,&f));
b.bar(*v.back().back()); // (*)
return 0;
}

This compiles. But when I omit the dereferencing in the marked line the
compiler complains (as it should):

error: no matching function for call to 'Bar::bar(const foo*&)'

The problem is: in the big program I do exactly the same. But here the
program compiles *whether* *or* *not* I dereference. How can that be?

There must be a conversion between "foo const*" and "foo". Two things to
watch out for:
1. Make sure you have copying and assignment under control. If in doubt,
disable both by declaring the according functions private and not
implementing them.
2. Watch out for implicitly callable constructors. If you have a ctor for
an A that takes a B as parameter, it can be invoked implicitly when
calling a function that takes an A with a B as parameter. To prevent that,
make sure that the constructor is declared as "explicit". Note that this
also applies to constructors that have effectively one argument due to
default values for the others.

Uli
 
R

Ralf Goertz

Ulrich said:
This may seem trivial to manage in small programs, but in larger programs
it is easy to lose track of who owns the objects pointed to here. Using
smart pointers helps. Not using dynamically allocated objects helps, too,
but might create different problems.

I know what you mean. But in my program those foo object are created at
the beginning, put in a map and then never touched again. So I am pretty sure
that that is not a problem. And my original design was somewhat different, I
changed it in the course of debugging.
There must be a conversion between "foo const*" and "foo". Two things to
watch out for:
1. Make sure you have copying and assignment under control. If in doubt,
disable both by declaring the according functions private and not
implementing them.

Good point. I added

private:
explicit foo();
explicit foo(const foo &);
foo & operator=(const foo&);

without implementing them. That gave problems with the map but after
commenting out those lines the program still compiled.
2. Watch out for implicitly callable constructors. If you have a ctor for
an A that takes a B as parameter, it can be invoked implicitly when
calling a function that takes an A with a B as parameter. To prevent that,
make sure that the constructor is declared as "explicit". Note that this
also applies to constructors that have effectively one argument due to
default values for the others.

That's it. After declaring every contructor explicit the compiler did
complain. So here is the small programm again which does not complain.
Thank you very much. Seems so easy when it is explained.


#include <vector>

struct foo { };

struct Bar {
void bar(const foo &) { }
void bar(bool) {} //needs to be explicit
};

int main() {
foo f;
Bar b;
std::vector<std::vector<const foo*> >v;
v.push_back(std::vector<const foo * >(1,&f));
b.bar(v.back().back()); // implicit conversion
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top