Nested class privacy leak: bug or feature?

Most programmers know classes in c++ can be nested, and the nested ones can be made private if they are not needed outside the implementation of the host class. The canonical example is a linked list:

struct data {};

class list
  {
    struct cart
      {
      data payload_;
      cart* next_;
      };
    cart first_;
  public:
  };

data in the code above is defined, to avoid making list a template. Altough that would be the obvious way, I want a simple host class example here, as what I am going to write about shows up everywhere, not just in templates.

The nested class cart is private, and §11 Member access control [class.access] of the standard says, roughly, that use of privately declared names will be prohibited by the compiler outside of member and friend functions. Thus, if we try to write

auto main(void) -> int
  {
  list::cart c;
  }

the compiler will intervene accordingly.

There is, however, a use case that is less clear–cut (brought to my attention by Aleksandra Cieplik, a student of mine) when you use the private nested class as return type of a public method:

struct data {};

class list
  {
    struct cart
      {
      data payload_;
      cart* next_;
      auto PublicFoo(void) -> void;
      };
    cart first_;
  public:
    auto GetFirstCart(void) -> cart&;
  };

That may not seem to be the wisest thing to do when implementing a list, but formally speaking, the standard does not seem to prevent this usage. After all, GetFirstCart is a method of list and cart is visible in its code. Hope is that, even though the GetFirstCart method is public, the compiler will effectively prevent us from storing or using its result outside of friends and methods of list, but, alas, here be trouble. Of course, as before, trying to use the nested class name to define a variable will be flagged as error by the compiler:

auto main(void) -> int
  {
  list l;
  list::cart c = l.GetFirstCart();

but other that that, anything goes:

  l.GetFirstCart().PublicFoo();

  auto c1 = l.GetFirstCart();
  decltype(l.GetFirstCart()) c2 = l.GetFirstCart();
  }

I might agree that allowing arbitrary clients of GetFirstCart to use the public interface of the result could be a reasonable explanation for letting the compiler turn a blind eye on our using a private nested class on the interface of a public method (what a wonderful opportunity for obscure hacks!), but I fail to see a rationale for allowing the definitions of c1 and c2 while prohibiting c.

Both gcc 4.9.1 and clang 3.5 agree on the above, and looking up the standard, in particular §11 Member access control [class.access] and §7.1.6.4 auto specifier [dcl.spec.auto] does not bring any insight, at least I did not find any. So, is this behaviour a bug or a feature? And if bug it is, bug in compilers or in the standard? Please let me know if you have an opinion on this.

Advertisements

5 Responses to Nested class privacy leak: bug or feature?

    • ljwo says:

      Thanks for the links. I still wonder, though, whether this is by design or by accident. The loophole (as I still see it) in c++98 was limited to template arguments, now it works with auto, and it seems like a greater possibility for confusion.

  1. A little correction: in listing 2, line 22 you probably meant decltype and not declspec. and also `l.GetFirstCart()` not just GetFirstCart() in parenthesis.

  2. Hi, I can see that the post is rather old, but I would still like to comment on it. I think the behavior you describe is in the spirit of C++. I cannot provide a reference, but I think Bjarne Stroustrup mentions it in “The Design & Evolution of C++” that the goal of C++ safety features is to prevent the inadvertent mistakes, but allow tricky things that developers do explicitly.

    A similar “safety gap” is observable even in C++03:
    http://melpon.org/wandbox/permlink/1RYesr5KiNO9OeTf
    http://melpon.org/wandbox/permlink/4cuchAxQw53lJx7e

    I would describe the situation as follows: if the author of the class explicitly allows access to private names, the compiler should respect that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: