C++ and Beyond 2012: Herb Sutter - You don't know [blank] and [blank]

Download this episode

Download Video

Description

Herb Sutter presents a "startling realization he had about C++11", and he thinks it may be a bit startling for others too. Tune in.

This was filmed at C++ and Beyond 2012

Download Herb's slides for this session.

Abstract:

In addition to the many new C++11 features that everyone's listing, it has dawned on me over the winter that there's actually another major change that isn't being talked about anywhere, or even being listed as a change in C++11 at all as far as I know, because I and other key experts and committee members I've asked didn't fully realize that we altered the basic meaning of not one but two fundamental keywords in C++. It's a change that has profound consequences, that rewrites and/or invalidates several pieces of pre-C++11 design guidance, and that's directly related to writing solid code in a concurrent and parallel world. This isn't just an academic change, either — everyone is going to have to learn and apply the new C++11 guidance that we'll cover in this session.

I plan to talk about it first at C&B, in a session tentatively titled as above — I'll fill in the keywords later. You may already guess a few keyword candidates based on the description above, and here's a final hint: You'll hardly find two C++ keywords that are older, or whose meanings are more changed from C++98 to C++11. (No, they aren't auto and register.)

Embed

Format

Available formats for this video:

Actual format may change based on video formats available and browser capability.

    The Discussion

    • SteveRichter

      does c++11 provide yield return and extension methods as we know them from C#?  Does it do away with header files?

       

    • felix9

      Thanks Smiley

    • Christian Semmler

      Sweet! Thanks a lot for sharing.

    • Roman Perepelitsa

      Applying const_cast to class members can cause undefined if the object itself was defined as const. Mutable doesn't have this problem.

      struct Foo {
      int value;
      void Mutate() const {
      const_cast<int&>(value) = 42;
      }
      };

      struct Bar {
      mutable int value;
      void Mutate() const {
      value = 42;
      }
      };

      const Foo foo = {};
      const Bar bar = {};

      int main() {
      foo.Mutate(); // Undefined Behavior.
      bar.Mutate(); // OK.
      }

    • tomkirbygre​en

      Ah the perfect end to 2012! This has been the best year for native code at Microsoft in well over a decade. Going into 2013 please keep up the investment in native, there has been much ground lost in both market and mindshare over the past ~12 years, but I passionately believe you guys can turn this around. Deliver the RTM parts previewed in the VC++ November CTP and you're well on your way to having IMO the best C++ 11 dev experience out there.

    • Charles
      @dot_tom: We're not letting up!! C
    • SteveRichter

      Why is const needed anyway?  C# does not have the concept.

      Another C++ request ...  enum class.  Have a built in ToString method or enable enum class to have member functions, or add extension methods to the language.  The purpose being to enable enum specific code, like Parse and ToString, to be called using dot notation from an enum instance.

      enum class Colors { red, white, blue } ;
      Colors color = Colors::red ;
      auto textColorName = color.ToString( )
      auto anotherColor = Colors::Parse( textColorName ) ;

      Bigger picture. Give me a native version of C#. Or enhance the struct handling capabilites of C#. ( C# cannot efficiently handle PIDLs used by windows shell. ) Microsoft to this day says that windows shell code written in C# is unsupported. A C# like native code language would be awesome.

       

    • Tianyu

      Steve, the whole point of C++ is to give you the tools to make such a class. Perhaps you can come up with an implementation and propose it as part of the standard STL?

    • PhrostByte

      Well, that's an interesting insight. It's going to take me a moment to wrap my head around this Smiley. I keep coming up with ways to invalidate it, but then go "oh, no, it still holds..."

    • petke

      Maybe a silly question. But, if mutable == const (== thread-safe)

      Shouldn't the following mean the same?

      mutable std::mutex<int> m1;
      const std::mutex<int> m2;

      If not, why?

    • turck3

      @petke - I believe the difference is in how you state intent to the compiler.

      When you have a const object, you're telling the compiler to forbid use of all non-const functions; the compiler can, in that manner, enforce the const/thread-safe guarantees that the class writer gave you.

      When you call something mutable under the new definition, you're stating 'I trust the author of this type to have made it entirely synchronized/thread-safe'. The compiler will then not restrict what methods you can call.

      I would argue that mutable is a keyword indicating your trust in the author, whereas const is about the author providing compiler-enforceable guarantees for the user.

      Code example:
      struct myStruct {
      const mutex m1;
      mutable mutex m2;

      void f1() const { m1.lock(); } //COMPILE-TIME ERROR
      void f2() const { m2.lock(); }
      };

      int main() {
      const myStruct x;
      x.f2(); //OK - author claims that myStruct is internally synchronized

      return 0;
      }

    • petke

      @turck3 Thanks. I still have an uneasy feeling about the new definition. If const is thread-safe. Why isn't the method std::mutex::lock defined as const (as its internally synchronized)?

    • XTF

      I think Herb is wrong. Const implies thread-safe, but thread-safe does not imply const, so the two are not equal/equivalent.

      Concurrent containers etc will certainly be thread-safe but not all functions will be const.

    • Arkadiy Belousov

      Doesn't this mean that "mutable" is an attribute of class rather than attribute of class' usage? In other words, we may be better off saying

      mutable class Mutex{/*...*/};

      rather than

      class A {
      mutable Mutex m;
      };


      ?

    • SteveRichter

      Steve, the whole point of C++ is to give you the tools to make such a class.

       

      but in practice Tianyu, you end up getting some inscrutable compile errors.

      Find the error in this code.  Note the bullshit compile error.

        void Tester2( unique_ptr<std::wstring> pString )  {  }  void CallTester2( )  {    unique_ptr<std::wstring> pString ;    Tester2( pString ) ;  }

       

       4 IntelliSense: "std::unique_ptr<_Ty, _Dx>::unique_ptr(const std::unique_ptr<_Ty, _Dx>::_Myt &) [with _Ty=std::wstring, _Dx=std::default_delete<std::wstring>]" (declared at line 1447 of "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory") is inaccessible c:\SkyDrive\democpp\Tester\Tester.cpp 379 14 Tester
      Error 3 error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' c:\skydrive\democpp\tester\tester.cpp 382 1 Tester

    • snkkid

      @PhrostByte it is very easy to invalidate this, constant member functions do not enforce referentially transparency (pure functions) even in C++11. You can still modify global or (class) static unsynchronized variables in constant member functions or modify unsynchronized data members marked as mutable.

      You can say this is a bug/undefined behavior (in the context of concurrent/parallel code) but this is an issue with the language/library if the standard say that constant member functions must be side-effect free but the language does not enforce this thus the compiler will never enforce this.

      From my point of view const does not guarantee thread safety, this is only a promise that can be silently broken. This is not particular useful.

      This change in C++11 is actually a breaking but silent change to existing code and you have no help from the language/compiler to find and fix any buggy code which is not C++11 compliant.

    • Matt_PD

      @SteveRichter: Clang gives a more readable diagnostic message:

      source.cpp:6:79: error: call to deleted constructor of 'std::unique_ptr<std::wstring>'
      void CallTester2( ) { std::unique_ptr<std::wstring> pString ; Tester2( pString ) ; }
                                                                           ^~~~~~~
      note: function has been explicitly marked deleted here unique_ptr(const unique_ptr&) = delete;
      

      See: http://liveworkspace.org/code/1zPqd0$1

      In other words, copy constructor is deleted -- in other words, unique_ptr is non-copyable.

      BTW, regarding enums, you can always implement something like this: http://www.ishani.org/web/2012/fancy-c-enums/

    • Gary

      Thanks Herb! Great lecture and explanation. Looking forward to the rest of the lectures as they get released.

    • PhrostByte

      @PhrostByte it is very easy to invalidate this, constant member functions do not enforce referentially transparency (pure functions) even in C++11. You can still modify global or (class) static unsynchronized variables in constant member functions or modify unsynchronized data members marked as mutable.

      You can say this is a bug/undefined behavior (in the context of concurrent/parallel code) but this is an issue with the language/library if the standard say that constant member functions must be side-effect free but the language does not enforce this thus the compiler will never enforce this.

      From my point of view const does not guarantee thread safety, this is only a promise that can be silently broken. This is not particular useful.

      This change in C++11 is actually a breaking but silent change to existing code and you have no help from the language/compiler to find and fix any buggy code which is not C++11 compliant.

      In other words, it's no different from most everything else in C++ -- helping you a good deal but still not "enforcing" anything, allowing you to do whatever the hell you want in the end Smiley

      A compiler may not be able to catch and warn about all instances of broken code (you're right, this is a breaking change), but there's a lot of room here for it to help.

    • Dmitriy​Vilkov

      Thanks!

    • Anonymous Coward

      Apparently I'm confused. I always though "const" meant "immutable"; now Herb is telling us that "const" means "mutable"? Wha..? Do an American English dictionary search for "mutable", por favor...

    • Charles

      @Anonymous Coward: Watch and actually listen to what Herb says...
      C

    • Andre Offringa

      Very interesting talk! Thanks a lot for sharing it.

      I would think that saying that both mutable and const *imply* thread safe is better than stating they equal thread safe. After all, const also implies "not allowed to perform non-const operations on" while mutable implies the opposite, so mutable != const. But that's just a nitpicking comment ;). The presentation is very insightful.

    • kip

      Thanks for this excellent talk, Herb !

      I have a question though. This mutable mutex story seems kind ow awkward to me.

      You said that "const" now means "thread-safe", and that "mutable" means "known to be thread-safe". If the mutex is thread-safe, as you said in your talk, shouldn't all its methods be declared const ? Therefore, the mutex would not have to be declared mutable.

    • Alessandro Stamatto

      @Kip : When you say a thing is a const you're saying "Look, think of this as immutable / assume I will not modify it" and for most cases it will be immutable/you will not modify. BUT if you modify it you have to guarantee that you will not mess concurrency/synchronization.

      And, in most cases, the compiler will not let you directly break your promise of immutable/non-modify. For that you have to explicitly cast the const thing to a non-const thing. OR you can say that thing is in fact mutable.

      Now when you say something is mutable you're saying "Look, this is not immutable but I guarantee that it will not cause problems with concurrency/synchronization, it's already synchronized"

      Const -> it's immutable, and as such thread-safe.
      Mutable -> it's mutable, but let me use as immutable because I guarantee it's thread-safe.

    • Andreas ​Pfaffenbich​ler

      hi herb!

      for me the point in this 'const/mutable' talk is, that you missed in your introducion a 'const':

      #include <utility>
      #include <future>
      #include <vector>
      using namespace std;
      /**/const/**/ vector<int> v(1000); // <--
      int main() {
      auto x = async([/**/&/**/]{ pair<int,vector<int>> z{ 1, v }; });
      auto y = async([/**/&/**/]{ pair<int,vector<int>> z{ 2, v }; });
      x.wait(); y.wait();
      }

      without this /**/const/**/, you have to 'know' that nobody modifies 'v'.

      am i right?

      best regards
      andreas pfaffenbichler

    • Kip Coul

      @Alessandro,

      Thanks for your answer, Alessandro. However, I can't say I fully agree, though I understand your point.

      The conclusion of what you said is "Const -> it's immutable, and as such thread-safe."
      This is precisely what puzzles me. Since a mutex is inherently thread-safe (thanks to some *internal* mechanism), why doesn't it expose its constness to the outside world ?
      I think that the stl standard breaks the encapsulation rule here.
      Basically, when you say that the lock method of a mutex is non-const, you're saying:
      "OK, by some internal mechanism, I have to modify some private variables of the mutex, in order to make it thread-safe, therefore it is non-const". Basically, you're exposing the internal working of the mutex by saying its lock method is non const, though it's thread safe.

      I hope I am clear in my explanation. Feel free to send me an email to further discuss this point (first-name dot last-name at gmail.com)

    • Erik W

      @Kip Coul

      I think the point is that const is not the same as thread safe. const implies thread safe, but thread safe does not imply const.

      The mutex is not const, and in fact that is what allows it to synchronize, if the mutex is not locked you need to lock it to synchronize, but you can't change the state of the mutex if it is const (despite of what Herb might have said, const still means immutable).

      That's where mutable comes in, because mutable (just like const) implies thread safe. But while const implies it since something that can't change by definition is thread safe, mutable is thread safe since you do you some form of synchronization.

      I think the key to understanding is the fact that thread safe != const, you can use other means of synchronization (for example a mutex). And if your class is not const then the mutex is not const either, so if the mutex's functions are non-const that's OK.

    Comments closed

    Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.