18

We will be upgrading to VS2015 soon, and I found this in the breaking changes list:

const elements

The C++ standard has always forbidden containers of const elements (such as vector or set). Visual C++ 2013 and earlier accepted such containers. In the current version, such containers fail to compile.

source

I was wondering if anyone knows if this also applies to a set. I know a map can still contain const pointers as keys, since they are const anyway.

An example:

std::set<const QObject*>

Can I still do this? I would think not, according to the post on the site of Microsoft.

cadaniluk
  • 15,027
  • 2
  • 39
  • 67
Houbie
  • 1,406
  • 1
  • 13
  • 25
  • 16
    `const T*` and `T* const` not the same thing. – uh oh somebody needs a pupper May 09 '16 at 08:38
  • 2
    The quote literally says that it applies to set. However, your code doesn't have much to do with the quote so you're safe :) – Lightness Races in Orbit May 09 '16 at 12:09
  • 2
    The confusion is reinforced by the nobly-intended-but-misleading style that omits the space before the asterisk (or ampersand on a reference). Writing `const QObject*` visually suggests that the `*` binds to QObject tighter than the `const` does. Moving the `const` doesn't help: `QObject const*`. It's like writing `return a * x+b * y;`. – Adrian McCarthy May 09 '16 at 16:33

2 Answers2

26

const QObject* is a pointer to a const QObject. The pointer itself is still modifiable. const QObject* const would make the pointer itself const.

Since the Microsoft article talks about const objects, which const QObject* is not, your example is fine.

cadaniluk
  • 15,027
  • 2
  • 39
  • 67
4

I know a map can still contain const pointers as keys, since they are const anyway.

std::set<T* const> has always been invalid, and std::map<int* const, int* const> s; has always been valid. The reason is because the allocator for std::set is std::allocator<Key>, whereas the allocator for std::map is std::allocator<std::pair<const Key, T>>. By definition, a std::allocator<const T> is ill-formed. If you want the map code to fail, you'll have to specify a custom allocator like this:

int i = 42;
int* const j = &i;
std::map<int* const, int* const,
    std::allocator<const std::pair<int* const, int* const>>> s{{j, j}};