Q:

Are const data member allowed to change outside the class?

If a class has a const reference data member that happens to change outside the scope of such class, is this undefined behaviour?
As an example, let's consider the following C++ code:
#include <iostream>

class A {
  int x;
public:
  A(int x): x(x){}
  void change(int y){
    x = y;
  }
  friend std::ostream & operator << (std::ostream & os, const A & a){
    os << a.x;
    return os;
  }
};

class B {
  const A & a;
public:
  B(const A & a) : a(a) {}
  friend std::ostream & operator << (std::ostream & os, const B & b){
    os << b.a;
    return os;
  }
};

int main(){
  A a(1);
  B b(a);
  std::cout << a << std::endl;
  std::cout << b << std::endl;
  a.change(2);
  std::cout << a << std::endl;
  std::cout << b << std::endl;
}

My compiler was able to execute it correctly and the debugger indicated that the x of B::a was changed.
Thank you for you help!

A:

It is not undefined behavior. The const reference that is a member of B only means that an instance of B may not change it via that reference. Because it is a reference, however, something else may change it -- including other members of B that have their own non-const reference to the same instance of A.
Compare the addition of the member c to your existing B class, and note that we are changing it successfully within B::changeA() via the non-const reference and also from C::change() down in main():
#include <iostream>

class A {
  int x;
public:
  A(int x): x(x){}
  void change(int y){
    x = y;
  }
  friend std::ostream & operator << (std::ostream & os, const A & a){
    os << a.x;
    return os;
  }
};

class C
{
    A& a;
public:
    C(A& a) : a{a} {}
    void change(int y) { a.change(y); }
};

class B {
  const A & a;
  C& c;
public:
  B(const A & a, C& c) : a(a), c{c} {}
  friend std::ostream & operator << (std::ostream & os, const B & b){
    os << b.a;
    return os;
  }
  void changeA(int y) { c.change(y); }
};

int main(){
  A a(1);
  C c(a);
  B b(a,c);

  std::cout << a << ' ' << b << '\n';

  a.change(2);
  std::cout << a << ' ' << b << '\n';

  b.changeA(3);
  std::cout << a << ' ' << b << '\n';

  c.change(4);
  std::cout << a << ' ' << b << '\n';
}

See it run live on Coliru, which prints:
1 1
2 2
3 3
4 4

A:

You may not change an object using a constant reference to it but you may change the object itself if it is not constant or using a non-constant reference to the object.
Consider the following demonstrative program.
#include <iostream>

int main() 
{
    int x = 10;

    int &rx = x;
    const int &crx = x;

    std::cout << "rx = " << rx << '\n';
    std::cout << "crx = " << crx << '\n';

    rx = 20;

    std::cout << "rx = " << rx << '\n';
    std::cout << "crx = " << crx << '\n';

    return 0;
}

Its output is
rx = 10
crx = 10
rx = 20
crx = 20

It is the same as using a pointer to constant data. For example
#include <iostream>

int main() 
{
    int x = 10;

    int *px = &x;
    const int *cpx = &x;

    std::cout << "*px = " << *px << '\n';
    std::cout << "*cpx = " << *cpx << '\n';

    *px = 20;

    std::cout << "*px = " << *px << '\n';
    std::cout << "*cpx = " << *cpx << '\n';

    return 0;
}

