1

I tried to bind a classes method from another class which is storing the first one's pointer, but it always gives me different value. What am I doing wrong?

If I pass class A by value (and of course modify class B to store by value) it's working.

#include <iostream>
#include <functional>

using namespace std;

class A {
public:
    A(double a, double b) : a(a), b(b) {}
    double mul(void) {return a*b;}

private:
    double a;
    double b;
};

class B {
typedef std::function<double(void)> function;

public:
    B(A* ap) : ap(ap) {}

    function a_mul = bind(&A::mul, ap);

private:
    A* ap;
};

int main() {
  A* a = new A(2,3);
  B b(a);

  cout << b.a_mul() << endl;

  return 0;
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
mooattyi
  • 13
  • 2
  • a_mul can't be initialized inline like that, so I presume this is not the exact code you're running. Aside from the a_mul initialization, it looks ok. So the problem must lie in something that's not being shown... – dlf May 22 '14 at 18:12
  • 1
    @dlf "a_mul can't be initialized inline like that" yes it can, welcome to C++11. – n. m. could be an AI May 22 '14 at 18:17
  • @n.m. Neat! But not Microsoft's (2012) C++11, apparently. :( – dlf May 22 '14 at 18:21
  • @mooattyi I just wanted to say that for a first question, this is a really good post. You provided an [SSCCE](http://sscce.org) that clearly demonstrates the problem. Keep it up! – Praetorian May 22 '14 at 18:24
  • @dlf 2012 is severely lacking in the 2011 department. Try 2013 or clang or gcc. – n. m. could be an AI May 22 '14 at 18:25
  • @n.m. Not really practical, I'm afraid. Hopefully SO can at least continue to educate me until I get to the point where I quit embarrassing myself by saying something's not possible when it's really just that my compiler won't do it. – dlf May 22 '14 at 18:28

1 Answers1

4

You're using a non-static data member initializer to initialize a_mul. The initial value depends on the value of ap. However, the definition of ap follows that of a_mul. This means that a_mul will be initialized prior to the initialization of ap in the constructor. At the time initilization occurs, ap has an indeterminate value, and thus your code has undefined behavior.

One way to fix this is changing the order of definition of the member variables:

class B {
typedef std::function<double(void)> function;

public:
    B(A* ap) : ap(ap) {}

    A* ap;
    function a_mul = bind(&A::mul, ap);
};

But a better fix would be reorder the data members, and initialize a_mul in the constructor's initializer list.

class B {

typedef std::function<double(void)> function;

private:
    A* ap;

public:
    B(A* ap) : ap(ap), a_mul(bind(&A::mul, ap)) {}

    function a_mul;
};
Praetorian
  • 106,671
  • 19
  • 240
  • 328