Search code examples
c++visual-studio-2008boostnoncopyable

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?


Solution

  • [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