Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VS2015 Update 1 bug, or bad C++: Why can't a friend class access its friend's protected destructor?

Tags:

c++

ice

The following appears to be a pattern employed by ZeroC ICE in the code it auto-generates, which appears to me to be a way they have made singletons (not sure why) for many releases of their tool now. Various compilers have no problem with it, until I found today that Visual Studio 2015 Update 1 (VS version 14.0.24720.00, VC++ version 19.00.23506) emits an error. Before Update 1, VS2015 also had no problem with it. I'm not sure whether it's a bug (regression?) in the VS2015 C++ compiler with Update 1, or bad (not standards-conformant) C++ code that other compilers let slide.

Here is an example of the code pattern:

class Foo {
protected:
    virtual ~Foo() {}

    friend class Foo_init;
};

class Foo_init {
public:
    Foo init;
};

static Foo_init staticFooInit;

VS2015 Update 1 emits these errors:

example.cpp(13): error C2248: 'Foo::~Foo': cannot access protected member declared in class 'Foo'
example.cpp(3): note: see declaration of 'Foo::~Foo'
example.cpp(1): note: see declaration of 'Foo'

I found one (as yet unanswered) ZeroC ICE forum post which seems related to this, but otherwise I haven't found out in my Google searching anything that convinces me whether this is a compiler issue or bad code. I admit I don't know ZeroC ICE very well, nor do I use C++ friend classes enough to have a deep understanding of what you can and can't do with them. I'm hoping someone more knowledgeable can shed some light on it.

like image 768
Richard Walters Avatar asked Dec 19 '15 23:12

Richard Walters


1 Answers

I am not 100% sure on your exact problem, but it reminds me of a problem I had a while ago, where forward declared classes would have an unexpected scope. this page cppreference class highlights the rules, that a forward-declared class has the most local scope. However, your example on my VS2015u3 does not fail either.

I think the fix is probably to forward declare the class which is a friend before the class, so that it has a well defined scope.

When you have a class such as

class Example {
     int someFunction( class SomeOtherClass & param );
};

The compiler treats declaration of SomeOtherClass which is within the local scope.

This means that

class Example {
     int someFunction( class SomeOtherClass & param );
};

class SomeOtherClass {
          ...
};

Declares three classes Example Example::SomeOtherClass and SomeOtherClass

Changing your example to

class Foo_init;

class Foo {
  protected:
    virtual ~Foo() {}

    friend Foo_init;
 };

class Foo_init {
  public:
    Foo init;
 };

 static Foo_init staticFooInit;

Should work

like image 117
mksteve Avatar answered Oct 19 '22 12:10

mksteve