Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost non-copyable weirdness

I have a class inheriting from boost::noncopyable; say, with header excerpt as follows:

class A : boost::noncopyable {
   ...
   blah
   ...
private:
   struct impl;
   boost::scoped_ptr<impl> m_impl;
};

Then in one of the projects of my solution, I have a class (that also happens to inherit from boost::noncopyable), one whose private members in an implementation detail is a reference to an object of type A, say, in the header excerpt:

class B : boost::noncopyable {
   ...
   blah
   ...
private:
   struct impl;
   boost::scoped_ptr<impl> m_impl;
};

and in the implementation excerpt (cpp):

struct B::impl {
    impl(A& a) : m_a(a) {}
    set_A(A& a) {m_a = a;}
    A& m_a;
    ...
}

B(A& a) : m_impl(new impl(a)) {}
...

Then in another project of my solution, I have a class C inheriting from B, say, with a header excerpt:

class C : public B {
   ...
   blah;
   ...
private: 
   struct impl;
   boost::scoped_ptr<impl> m_impl;
};

and in the implementation excerpt (cpp):

struct C::impl {
    impl(A& a) : m_a(a) {}
    void set_A(A& a) {m_a = a;}
    A& m_a;
};

C(A &a) : B(a), m_impl(new impl(a)) {}
...

But when I try to build in MSVC++ 2008, I get the following error:

error C2248: 'boost::noncopyable_::noncopyable::operator =' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'
see declaration of 'boost::noncopyable_::noncopyable::operator ='
error C2248: 'boost::scoped_ptr<T>::operator =' : cannot access private member declared in class 'boost::scoped_ptr<T>' with T = A::impl
This diagnostic occurred in the compiler generated function 'A& A::operator =(const A&)'

The compiler only has an issue with C's set_A function, not B's set_A. Appreciate if anyone has any ideas on this and can shed some light? Thanks as always for your interest.

Edit:

To summarize, what I don't understand here is why the compiler is picky about when to apply the error regarding boost::noncopyable. When I comment out the set_A(..) function in class C, everything compiles OK. But when I keep it, it gives the error, whereas it doesn't have any problems with the same in class B. I also edited the error message above slightly to give more detail. I note here that it stated something about a compiler generated function. Could it be that this happened only with class C for some reason? Why?

like image 604
squashed.bugaboo Avatar asked Sep 20 '12 02:09

squashed.bugaboo


1 Answers

[EDIT]

First of all, now I better understand your question, but I still do not understand why don't you want to change your implementation to:

struct C::impl {
    impl(A& a) : m_a(&a) {}
    void set_A(A& a) {m_a = &a;}
    A* m_a;
};

With A non-copyable this will simple do not work:

void set_A(A& a) {m_a = a;}

Anyway:

This error:

error C2248: 'boost::scoped_ptr::operator =' : cannot access private member declared in class 'boost::scoped_ptr' with T = A::impl

is because boost::scoped_ptr<T> is non-copyable and this fact is not related to the fact that your A class is not copyable.

This error:

This diagnostic occurred in the compiler generated function 'A& A::operator =(const A&)'

is for sure because of one of XXX::set_A(A& a) { m_A = a; } functions. In such function A::operator =(const A&) is required - and because it is not defined compiler try to define the default one. Default one will copy members one by one - and one of A members is non-copyable boost::scoped_ptr<A::impl>.

Then the most important for you question - why only one error - not for both XXX::set_A(A& a) { m_A = a; } methods?

I tested simplified version of your case in my g++ 4.5.x enviroment. The diagnosis is very similar to yours - and the effect is very similar - only one set_A function is complained - the first one. This is because A& operator = (const A&) is needed for both - but generate only for the first one. g++ gives the excelent diagnosis:

../src/AnExample.cpp:24:32: note: synthesized method 'A& A::operator=(const A&)' first required here

My example and diagnosis:

class noncopyable {
private:
   noncopyable(const noncopyable&);
   noncopyable& operator = (const noncopyable&);
};

class A {
  noncopyable m;
};

class B {
  B(A& a) : a(a) {}
  void set_A(A& a) { this->a = a; } // line 24
  A& a;
};

class C {
  C(A& a) : a(a) {}
  void set_A(A& a) { this->a = a; }
  A& a;
};

make all 
Building file: ../src/AnExample.cpp
Invoking: Cygwin C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/AnExample.d" -MT"src/AnExample.d" -o "src/AnExample.o" "../src/AnExample.cpp"
../src/AnExample.cpp: In member function 'A& A::operator=(const A&)':
../src/AnExample.cpp:15:17: error: 'noncopyable& noncopyable::operator=(const noncopyable&)' is private
../src/AnExample.cpp:18:9: error: within this context
../src/AnExample.cpp: In member function 'void B::set_A(A&)':
../src/AnExample.cpp:24:32: note: synthesized method 'A& A::operator=(const A&)' first required here 
make: *** [src/AnExample.o] Error 1
src/subdir.mk:18: recipe for target `src/AnExample.o' failed
like image 112
PiotrNycz Avatar answered Oct 20 '22 14:10

PiotrNycz