Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Realizing that C++’s “special” member functions may be declared private

Don't do this anymore! Just delete them:

    MyClass& operator=(const MyClass&) = delete;
Private-really-means-deleted was a cool and very useful trick before C++11. So useful, that it was a shame to require secret knowledge and aha moments to use. So they just made it a normal feature of the language. There's also a way to explicitly use the default implementation:

    MyClass& operator=(const MyClass&) = default;


There is an obscure pitfall of making a class noncopyable by making the copy constructor private.

Consider the following class:

  class X { 
   private:
     X& (const X&); // not defined
   public:
     X bar() {
        X x = ......;
        return x;
     }
   };
Due to programmer error, an instance of X is returned by value despite the class being noncopyable. The copy constructor being private doesn't help as bar() is a method of X. This will compile and link, despite the copy constructor being undefined. I will leave the reason for this as an exercise for the reader.


It might compile, but it won't link.


It will likely link, since both clang and gcc will perform RVO on bar(), so the copy constructor won't be called.


Interesting, I didn't know about `delete`.

Come to think of it, the trick to make something private in order to "remove" it is one of these very few areas where C++ makes you pay for something you don't use, so I'm not surprised that there is now a special keyword (well, a repurposed keyword) to address that.


A declared-private but unimplemented method shouldn't have any runtime cost. =delete is just a syntactic convenience.


> Private-really-means-deleted was a cool and very useful trick before C++11

Rather, until every compiler you need to target supported this specific C++11 feature. In other words, it's still a cool and very useful trick ;)


This is my ignorance speaking, but with the gcc, clang, and msvc all fully supporting C++11, where are the holdups?


There are people which, for reasons good and bad, use very old versions of their tools. There are also C++ compilers other than gcc, clang and msvc.


And to share some of the less horrible reasons to be on older versions of tools:

You can't just download the latest version of MSVC and target the Xbox 360 or Xbox One with it - their SDK integrations aren't instantly forward compatible. Even if you could, you might fail cert - Microsoft requires you to use specific compiler versions, and specific compiler flags, in an effort to improve security. Keep in mind the 360 wasn't even x86 - just because the x86 compiler had been sufficiently tested for regressions for release, doesn't mean QA was done vetting the PPC compiler.

While Sony has been contributing upstream much of the clang work they've done to support the PS4, I don't know that everything has - and even if it has, I'd rather not spend the time to try and recompile clang myself just to embrace the most bleeding edge of compiler tech. I'd much rather just keep to whatever version Sony supplies. Some of their APIs come as binaries for C++ - I do not want to mix and match compiler versions!

...the above reasons have forced me to have multiple MSVC versions installed at the same time. Which isn't all that annoying until you target pre-release Windows 8 because Microsoft is your publisher and wants ModernUI apps, and you have to wipe - and reinstall - every few months to get on the latest version. And if you install in the wrong order, you get to restart from the beginning.

A number of game studios buy MSVC straight up instead of MSDN subscriptions for various reasons, so MSVC upgrades may cost tens of thousands of dollars (a bit under $1k per head last I checked.) Even if MSVC upgrades are 'free' for you (e.g. you have MSDN subscriptions), upgrading still involves:

1) Getting matching updated binaries for any third party C++ SDKs 2) Testing to ensure the optimizer hasn't found new an exciting ways to break your code via exploitation of (previously benign) undefined behavior. 3) Dealing with an updated IDE frontend, with all it's bugs, unupdated plugins, etc. 4) Reworking build scripts to correctly invoke the new build 5) (Re)installing MSVC across the entire studio, all build machines, etc.

Doing a VS2008 -> VS2010 upgrade of a large codebase required a rewrite of most of our build configuration, in my experience (Microsoft revamped things in terms of MSBuild.) VS2010 -> VS2012 was much less harsh - I could even share build configurations when we had to support VS2010 and VS2012 simultaneously - but getting everyone up and running again after the upgrade was still days of downtime for no gains on our end, except regaining the ability to pass certification.

More in the "bad" column: At home, I have hundreds of projects in my I:\home\projects\dead\ folder. As a result, I still keep VS2008 installed. (I also have VS2013 installed - I may skip VS2015 in favor of VS2016/2017? We'll see.)


There are tons of C++ compilers to chose from, not everyone uses only those three.

For example on the embedded space many toolchains are still C++98, not even C++03.


Icc


ICC supports delete! Auto type deduction and uniform initialization syntax are another story...


> that it was a shame to require secret knowledge and aha moments to use

But Myers had this aha moment about private constructors in 1988! Since then, this has been covered in countless books, tutorials and coding convention documents.

A newbie still has to read something in order to learn about "= delete". This is not "discoverable" just by experimenting with the language!

Knowing that delete is a keyword, and that there are declarations of the form "specifiers fun-declarator = blurb" you are very unlikely to discover, on your own, that the blurb may be the keyword "delete", and that this actually compiles and has a certain useful effect.

However, the combination of constructors and "private:" is discoverable, as Myers' 1988 aha moment shows. It's a logical combination of independent features.

It's okay for techniques in languages to be discoverable logical combinations of features rather than arbitrary syntax thrown in.

It's also okay for the culture which surrounds a language to have a body of techniques which are carried in that culture, rather than shoehorned into the language parser.


Alternative view: if you must use C++, stick to nothing later than C++2003.

Anyway, declaring a constructor " = delete" isn't the same thing as making it private. If it's private, the code in your class scope can still use it. If you can't trust your class private code to do things correctly, then you're screwed; go join IT and write backup shell scripts. So basically this "= delete" is just another ear growing out of the elbow of C++.


The reason for testing and static typing is that you can't trust yourself to be perfect. I want to declare that I won't do things that don't make sense, so the tools will tell me if I do them unintentionally.


In 1998 C++, we can solve the problem of how to make a class non-copyable, even to code that is in its class scope.

We can create a dummy class which has a private copy constructor that is not implemented:

  class noncopyable {
  private:
    noncopyable(const noncopyable &);
  };
then simply make this a data member of a class that you don't wish to be copyable:

  class whatever {
  private:
    noncopyable nc;
  };
The default copy constructor generated by the C++ compiler performs a member-for-member copy, which involves copying nc. That is not possible, so in effect that copy constructor is defeated, not unlike by "= delete".

Alternatively use inheritance to mix this in as a trait:

  class whatever : private noncopyable {
    // ...
  };


Why?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: