C++ Feature Proposal: = default

470 views
Skip to first unread message

Daniel Bratell

unread,
Sep 24, 2014, 9:10:13 AM9/24/14
to chromi...@chromium.org
What:

Allowing =default
in function definitions and function declarations.

Why:
In C++ there are a number of operators and functions that are automatically generated in a class, such as default constructor, copy constructor, assignment operator, move operator and destructor. In many cases that is perfectly fine, but in some cases the default rules for those are not good enough.

Use case 1:
Sometimes you need a trivial default constructor but it will not be automatically generated if there is another constructor. Using =default allows you to create the trivial default constructor without actually implementing it yourself (and if you implement it yourself it will no longer have a chance to be "trivial" from a language perspective).

struct A
{
    A() = default;
    A(int) { m_1 = "Hello"; }

    std::string m_1;
};

Use case 2:
Generated constructors/operators are public. Only chance to make them private or protected is to write them yourself. Using =default you can change the accessibility of them without actually having to write any code.

struct A
{
    A* createA() { return new A(); }
private:
    // Make it impossible to put A object on the stack.
    A() = default;
    A(const A&) = default;

    std::string m_1;
};

Use case 3:
The default functions are by default set to be inlined (a hint a compiler can choose to follow (always in gcc) or ignore (often in clang)) so that if a class is large you may need to manually write the operators outline to avoid that. That has a certain cost and risk that might make it hard choice. Also, if you write them yourself a compiler can't ever know that they are "trivial" and can't do certain other optimizations.

In C++ 11 you can instead write

struct A
{
    A();
    A(const A&);
    ~A();
    void operator=(const A&);

    std::string m_1;
    std::string m_2;
    std::string m_3;
    std::string m_4;
    std::string m_5;
    std::string m_6;
    std::string m_7;
    std::string m_8;
};

A::A() = default;
A::A(const A&) = default;
A::~A() = default;
A& A::operator=(const A&) = default;

If it's important to combine "detected as trivial" and "not inline", something that is not possible at all in earlier C++, you can use the NEVER_INLINE macro (here expanded for gcc):

struct A
{
    __attribute__((noinline)) A() = default;
}

For people thinking this is something best left to compilers, I will say that I agree, but for a compiler to have a chance to make the right decisions we need full program optimization. Full program optimization is not available until we shrink chromium or get hardware and software improvements that allow chromium to be fully analyzed an all platforms, especially those where this matters most.

I don't expect this use case to be used much, but by using it at a few select places you do get a noticeable impact.

Where:
When not writing a manual implementation would result in the compilers doing the wrong things because of the way C++ is defined, and it is wrong enough to be noticed, or when it saves some writing of constructors.

/Daniel

David Michael

unread,
Sep 24, 2014, 11:16:35 AM9/24/14
to bratell at Opera, chromi...@chromium.org
+1 to allowing default, in particular for your Use Case 1 and Use Case 2.

I'm not swayed by use case 3, and I don't condone using default for this Use Case 3. In general, I'd rather let the compiler decide. When this came up before, we found that doing it saved some binary size on GCC and increased binary size on clang. I don't think anybody ever tried it for MSVS. We shouldn't add code complexity in order to get small space savings on 1 toolchain.
...if we find out that it's a more clear win, we can re-evaluate.

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

Daniel Bratell

unread,
Sep 24, 2014, 11:48:21 AM9/24/14
to David Michael, chromi...@chromium.org
On Wed, 24 Sep 2014 17:15:57 +0200, David Michael <dmic...@chromium.org> wrote:

+1 to allowing default, in particular for your Use Case 1 and Use Case 2.

I'm not swayed by use case 3, and I don't condone using default for this Use Case 3. In general, I'd rather let the compiler decide. When this came up before, we found that doing it saved some binary size on GCC and increased binary size on clang. I don't think anybody ever tried it for MSVS. We shouldn't add code complexity in order to get small space savings on 1 toolchain.
...if we find out that it's a more clear win, we can re-evaluate.

That is why I wrote that that use case was for carefully selected places. For instance adding explicit constructors in Angle made the binary 200 KB smaller (10-20% of that whole subproject?). With =default it would have been only a few lines of code.

The list in the bug was just a list of suspiciously large code in collections and each one would have had to be analyzed to see if something should be done and what that would be in that case.

Binary size has a very low priority (after features, maintainability, performance) for the general chromium project but that doesn't mean code efficiency is completely irrelevant, and with =default the maintenance cost of some changes is greatly reduced which is a good thing.

/Daniel

Nico Weber

unread,
Sep 24, 2014, 11:52:41 AM9/24/14
to Daniel Bratell, David Michael, chromi...@chromium.org
I'd like to wait with this, since explicitly defaulted move constructors don't work right in MSVS2013 ( http://msdn.microsoft.com/en-us/library/hh567368.aspx#defaultedanddeleted ).

Viet-Trung Luu

unread,
Sep 24, 2014, 11:59:41 AM9/24/14
to Daniel Bratell, David Michael, chromi...@chromium.org
In general, we already require nontrivial constructors (and destructors) to be defined out of line. For default constructors (and destructors), "= default" isn't very compelling. But it's mostly advantageous for copy constructors.

(In any case, the effect is small, since we mostly have noncopyable classes anyway.)


/Daniel

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.

Hendrik

unread,
Sep 24, 2014, 12:03:18 PM9/24/14
to chromi...@chromium.org, bra...@opera.com, dmic...@chromium.org
We could simply disallow using =default on move constructors.  It won't compile in MSVC, so it would be difficult to make a mistake.

Case 1 and 2 are very persuasive reasons to allow it.


On Wednesday, September 24, 2014 8:52:41 AM UTC-7, Nico Weber wrote:
I'd like to wait with this, since explicitly defaulted move constructors don't work right in MSVS2013 ( http://msdn.microsoft.com/en-us/library/hh567368.aspx#defaultedanddeleted ).

On Wed, Sep 24, 2014 at 8:47 AM, Daniel Bratell wrote:

Elliot Glaysher (Chromium)

unread,
Sep 24, 2014, 1:14:58 PM9/24/14
to Viet-Trung Luu, Daniel Bratell, David Michael, chromi...@chromium.org
On Wed, Sep 24, 2014 at 8:59 AM, Viet-Trung Luu <viettr...@chromium.org> wrote:
On Wed, Sep 24, 2014 at 8:47 AM, Daniel Bratell <bra...@opera.com> wrote:
On Wed, 24 Sep 2014 17:15:57 +0200, David Michael <dmic...@chromium.org> wrote:

+1 to allowing default, in particular for your Use Case 1 and Use Case 2.

I'm not swayed by use case 3, and I don't condone using default for this Use Case 3. In general, I'd rather let the compiler decide. When this came up before, we found that doing it saved some binary size on GCC and increased binary size on clang. I don't think anybody ever tried it for MSVS. We shouldn't add code complexity in order to get small space savings on 1 toolchain.
...if we find out that it's a more clear win, we can re-evaluate.

That is why I wrote that that use case was for carefully selected places. For instance adding explicit constructors in Angle made the binary 200 KB smaller (10-20% of that whole subproject?). With =default it would have been only a few lines of code.

The list in the bug was just a list of suspiciously large code in collections and each one would have had to be analyzed to see if something should be done and what that would be in that case.

Binary size has a very low priority (after features, maintainability, performance) for the general chromium project but that doesn't mean code efficiency is completely irrelevant, and with =default the maintenance cost of some changes is greatly reduced which is a good thing.

In general, we already require nontrivial constructors (and destructors) to be defined out of line. For default constructors (and destructors), "= default" isn't very compelling. But it's mostly advantageous for copy constructors.

In general, I'm very excited at the prospect of case 3, moving more copy constructors/operator=s to the implementation file. This will make what's already there more robust (we have a lot of manually written default constructors is cc files, and that's fragile), and adding "operator=(...) = default;" might have a positive effect in some places.

James Robinson

unread,
Sep 24, 2014, 1:42:17 PM9/24/14
to hendrikw, Chromium-dev, Daniel Bratell, David Michael
That article does not say that =default on move constructors does not compile, it says that they don't work correctly.  That's a big difference.  Having code that works on some platforms and miscompiles on MSVS is very bad and hard to discover.

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.

Hendrik

unread,
Sep 24, 2014, 1:52:23 PM9/24/14
to chromi...@chromium.org, hend...@chromium.org, bra...@opera.com, dmic...@chromium.org
I, of course, tried compiling it before posting :)

"error C2610: 'A::A(A &&)' : is not a special member function which can be defaulted"


On Wednesday, September 24, 2014 10:42:17 AM UTC-7, James Robinson wrote:
That article does not say that =default on move constructors does not compile, it says that they don't work correctly.  That's a big difference.  Having code that works on some platforms and miscompiles on MSVS is very bad and hard to discover.

James Robinson

unread,
Sep 24, 2014, 2:11:27 PM9/24/14
to hendrikw, Chromium-dev, Daniel Bratell, David Michael
OK, if we could make that consistent across all platforms then it'd be slightly better.  But that means =default is only really useful for copy constructors, which we don't tend to have a ton of.  Are there examples in our codebase today of copy constructors that we would rather =default?

I'm with Nico that we should hold off on this until we have consistent cross-toolchain support.  If we could make =default for move constructors and assignment operators produce the same compile error on all platforms that'd be slightly better but then it wouldn't be super useful.

- James

James Robinson

unread,
Sep 24, 2014, 2:14:25 PM9/24/14
to Daniel Bratell, chromi...@chromium.org
On Wed, Sep 24, 2014 at 6:09 AM, Daniel Bratell <bra...@opera.com> wrote:
Use case 1:
Sometimes you need a trivial default constructor but it will not be automatically generated if there is another constructor. Using =default allows you to create the trivial default constructor without actually implementing it yourself (and if you implement it yourself it will no longer have a chance to be "trivial" from a language perspective).

struct A
{
    A() = default;

Writing "A() {};" is fewer characters and clearer.
 
    A(int) { m_1 = "Hello"; }

    std::string m_1;
};

Use case 2:
Generated constructors/operators are public. Only chance to make them private or protected is to write them yourself. Using =default you can change the accessibility of them without actually having to write any code.

struct A
{
    A* createA() { return new A(); }
private:
    // Make it impossible to put A object on the stack.
    A() = default;
    A(const A&) = default;

You can accomplish this today by just declaring A() private and giving it a definition.  Again, A() {} is fewer characters.
 

    std::string m_1;
};

Use case 3:
The default functions are by default set to be inlined (a hint a compiler can choose to follow (always in gcc) or ignore (often in clang)) so that if a class is large you may need to manually write the operators outline to avoid that. That has a certain cost and risk that might make it hard choice. Also, if you write them yourself a compiler can't ever know that they are "trivial" and can't do certain other optimizations.

This is only really important for copy constructors and assignment operators, since the body of a trivial constructor or destructor is trivial to write.  I don't think we have enough copy constructors to make this a big issue in our codebase.

- James

Hendrik

unread,
Sep 24, 2014, 2:36:26 PM9/24/14
to chromi...@chromium.org, bra...@opera.com
I agree with you, but:

If I did want to make the copy constructor private, and the copy constructor is non-trivial (i.e. many member variables), it becomes a source of potential errors when first implemented, or when new member variables are added (same goes for ==operator).  These can be sometimes be hard to catch.  

Though, not implementing a copy constructor yourself sometimes causes issues too (e.g. owned pointers to data, hopefully no one does this anymore).

That said, I don't run into the need for private copy constructor often, so I don't really care which way this goes.


On Wednesday, September 24, 2014 11:14:25 AM UTC-7, James Robinson wrote:

Daniel Bratell

unread,
Sep 24, 2014, 2:46:06 PM9/24/14
to James Robinson, chromi...@chromium.org
On Wed, 24 Sep 2014 20:13:41 +0200, James Robinson <jam...@chromium.org> wrote:



On Wed, Sep 24, 2014 at 6:09 AM, Daniel Bratell <bra...@opera.com> wrote:
Use case 1:
Sometimes you need a trivial default constructor but it will not be automatically generated if there is another constructor. Using =default allows you to create the trivial default constructor without actually implementing it yourself (and if you implement it yourself it will no longer have a chance to be "trivial" from a language perspective).

struct A
{
    A() = default;

Writing "A() {};" is fewer characters and clearer.

I agree, though by having  a user defined constructor it can no longer be "trivial" which means that some compiler/library optimizations get disabled. And clearer is a matter of what you are used to. Right now nobody uses = default so {} is clearly clearer. That might change if we start using it.

Sorry about the big font by the way. For some reason the font size displayed when I compose is smaller than normal so I thought I had to increase it to get "normal" size.

 
    A(int) { m_1 = "Hello"; }

    std::string m_1;
};

Use case 2:
Generated constructors/operators are public. Only chance to make them private or protected is to write them yourself. Using =default you can change the accessibility of them without actually having to write any code.

struct A
{
    A* createA() { return new A(); }
private:
    // Make it impossible to put A object on the stack.
    A() = default;
    A(const A&) = default;

You can accomplish this today by just declaring A() private and giving it a definition.  Again, A() {} is fewer characters.

You would still get a an automatic public copy constructor. (And for the difference between {} and =default see above)

Use case 3:
...
This is only really important for copy constructors and assignment operators, since the body of a trivial constructor or destructor is trivial to write.  I don't think we have enough copy constructors to make this a big issue in our codebase.

We don't have many hand written copy constructors or assignment operators but I think there is somewhere in the order of MB of generated ones inlined in the machine code. STL containers, algorithms and our own STL inspired containers and template code love copying and assigning objects. I don't say that this is wrong. If an object has to move from one place in the memory to another, then there has to be machine code that does that. I am just challenging the idea that we don't have many of them.

But if I understand your argument (please correct me if I've misunderstood it), it is that you don't think =default should be allowed because there are other ways to accomplish a similar behaviour and that the places where it would be useful would be few and having =default would be confusing/distracting to people reading the code?

I can agree that it is one of the new things in C++ that not everyone will know immediately (I didn't know about it until 9 months ago when I realised I needed it. :-) ), but I argue that it is way easier to understand than most language features.

/Daniel

Alex Vakulenko

unread,
Sep 24, 2014, 2:48:44 PM9/24/14
to bra...@opera.com, James Robinson, chromi...@chromium.org
I think the main use case for Chromium code base is the importance of =default when using DISALLOW_COPY_AND_ASSIGN(), at least in its current implementation. Here is an example:

class Foo {
  public:
   void SetValue(const std::string& value);
   const std::string& GetValue() const;

  private:
   std::string value_;
};

This happily compiles. Then you do this:

Alex Vakulenko

unread,
Sep 24, 2014, 2:50:44 PM9/24/14
to bra...@opera.com, James Robinson, chromi...@chromium.org
I'm a bit send-trigger happy, I guess..

So, to continue...

Then you change your class:

class Foo {
  public:
   void SetValue(const std::string& value);
   const std::string& GetValue() const;

  private:
   std::string value_;
   DISALLOW_COPY_AND_ASSIGN(Foo);
};

////

Foo foo;

And this doesn't compile anymore, because DISALLOW_COPY_AND_ASSIGN() provides non-default constructor which disables the default one.

To fix this:

class Foo {
  public:
   Foo() = default;
   void SetValue(const std::string& value);
   const std::string& GetValue() const;

  private:
   std::string value_;
   DISALLOW_COPY_AND_ASSIGN(Foo);
};

James Robinson

unread,
Sep 24, 2014, 2:54:14 PM9/24/14
to Alex Vakulenko, Daniel Bratell, chromi...@chromium.org
On Wed, Sep 24, 2014 at 11:50 AM, Alex Vakulenko <avaku...@chromium.org> wrote:
And this doesn't compile anymore, because DISALLOW_COPY_AND_ASSIGN() provides non-default constructor which disables the default one.

To fix this:

class Foo {
  public:
   Foo() = default;

or, Foo() {}

or Foo();

and in the .cc Foo::Foo() {}

These are common today.  This is nothing new with C++11, C++11 just provides a different syntax for doing the exact same thing.

- James

James Robinson

unread,
Sep 24, 2014, 2:58:14 PM9/24/14
to Daniel Bratell, chromi...@chromium.org
On Wed, Sep 24, 2014 at 11:45 AM, Daniel Bratell <bra...@opera.com> wrote:

I agree, though by having  a user defined constructor it can no longer be "trivial" which means that some compiler/library optimizations get disabled.

Examples?

We don't have many hand written copy constructors or assignment operators but I think there is somewhere in the order of MB of generated ones inlined in the machine code. STL containers, algorithms and our own STL inspired containers and template code love copying and assigning objects. I don't say that this is wrong. If an object has to move from one place in the memory to another, then there has to be machine code that does that. I am just challenging the idea that we don't have many of them. 

But if I understand your argument (please correct me if I've misunderstood it), it is that you don't think =default should be allowed because there are other ways to accomplish a similar behaviour and that the places where it would be useful would be few and having =default would be confusing/distracting to people reading the code?

We have a fairly large caveat on toolchain support for = default and a relatively small set of useful use cases today, so I'm not sure how much of a benefit it would allow.  If we could were using move semantics and had full toolchain support, then =default for move and copy constructors would be wonderful.  We don't have those, though, so I'm not sure we would get much benefit out of using = default today.

If you can point to some code that we have today that would get better with =default and we could make the toolchain situation uniform then I think the case for = default would be more compelling.  Today it wouldn't buy us much.


I can agree that it is one of the new things in C++ that not everyone will know immediately (I didn't know about it until 9 months ago when I realised I needed it. :-) ), but I argue that it is way easier to understand than most language features.

That's a general argument and not very useful in the concrete.  This thread is about a concrete feature and we should consider the concrete pros and cons of it.

- James
 


/Daniel


Alex Vakulenko

unread,
Sep 24, 2014, 3:08:52 PM9/24/14
to James Robinson, Daniel Bratell, chromi...@chromium.org
I agree, though by having  a user defined constructor it can no longer be "trivial" which means that some compiler/library optimizations get disabled.

Examples?

Here is a very contrived example:

struct IntArray {
  IntArray() = default;
  IntArray(int first_element) : array_{first_element} {}
  std::vector<int> array_;
};

This is copyable AND movable class (having default copy and move constructor/operator=()).

struct IntArray {
  IntArray() {}
  IntArray(int first_element) : array_{first_element} {}
  std::vector<int> array_;
};

And this is NOT movable (user-provided default constructor kills generated move constructor/assignment operator).



James Robinson

unread,
Sep 24, 2014, 3:08:59 PM9/24/14
to Alex Vakulenko, Daniel Bratell, chromi...@chromium.org
On Wed, Sep 24, 2014 at 12:06 PM, Alex Vakulenko <avaku...@google.com> wrote:

I agree, though by having  a user defined constructor it can no longer be "trivial" which means that some compiler/library optimizations get disabled.

Examples?

Here is a very contrived example:
...
And this is NOT movable (user-provided default constructor kills generated move constructor/assignment operator).

That's pretty much completely irrelevant since we can't take advantage of move semantics in STL (since we don't use a library that supports C++11) or in our code (since we don't have std::move() or allow any use of rvalue semantics).

Are there any examples that are actually relevant to chromium today?  I already mentioned above the usefulness of = default in a world where we can take advantage of move semantics, but that's not a world we live in.

- James

Daniel Bratell

unread,
Sep 24, 2014, 3:23:41 PM9/24/14
to James Robinson, chromi...@chromium.org
On Wed, 24 Sep 2014 20:57:38 +0200, James Robinson <jam...@chromium.org> wrote:

On Wed, Sep 24, 2014 at 11:45 AM, Daniel Bratell <bra...@opera.com> wrote:

I agree, though by having  a user defined constructor it can no longer be "trivial" which means that some compiler/library optimizations get disabled.

Examples?



That's a general argument and not very useful in the concrete.  This thread is about a concrete feature and we should consider the concrete pros and cons of it.

See the Angle example in an earlier post. With = default third_party/angle/src/compiler/translator/ShaderVars.cpp could have been 40 lines instead of 150 lines. The addition of that code shaved several hundred KB of the binary size (often smaller code is also faster but I haven't seen any performance numbers) so it is 150 lines well spent. 40 lines and less room for forgetfulness would have been even better though.

/Daniel

Hendrik

unread,
Sep 24, 2014, 4:16:45 PM9/24/14
to chromi...@chromium.org, avaku...@google.com, bra...@opera.com
On Wednesday, September 24, 2014 12:08:59 PM UTC-7, James Robinson wrote:

That's pretty much completely irrelevant since we can't take advantage of move semantics in STL (since we don't use a library that supports C++11) or in our code (since we don't have std::move() or allow any use of rvalue semantics).

Wait... what?

Why is this?  I assume that this isn't true on all platforms, right?

Even if this is true, we would continue writing code that is not future proof.  This isn't a good idea.

Someone just told me he was disappointed in me for agreeing with you, basically he stated that we shouldn't be talking about character count, =default the code specifies intent, which is important.

This, along with the other arguments made, (move semantics issue, possible binary size, less error prone, convenience, possible optimizations the compiler could make), I would now like to see =default included.

Peter Kasting

unread,
Sep 24, 2014, 6:27:17 PM9/24/14
to James Robinson, hendrikw, Chromium-dev, Daniel Bratell, David Michael
On Wed, Sep 24, 2014 at 11:10 AM, James Robinson <jam...@chromium.org> wrote:
OK, if we could make that consistent across all platforms then it'd be slightly better.  But that means =default is only really useful for copy constructors, which we don't tend to have a ton of.  Are there examples in our codebase today of copy constructors that we would rather =default?

Copy constructors aren't the only case.  There are a lot of places in the frontend code where I've been required to implement a default-constructor in order to use a class with STL containers (because I wrote a non-default constructor).

That said, the frontend code also does use a lot of copyable types that we've written explicit copy constructors for.  It's a much more common pattern than e.g. in Blink code.

On Wed, Sep 24, 2014 at 11:13 AM, James Robinson <jam...@chromium.org> wrote:
Writing "A() {};" is fewer characters and clearer.

It's shorter, but it's not necessarily clearer.  "= default" implies that you intend this constructor to do whatever the default thing the compiler would do.  "{}" implies that you intend the constructor to do nothing.  Those are slightly different, especially when modifying a class later by adding more data members.

I think in the STL case I give above, for example, "= default" is clearer about implying that only the presence of the constructor is relevant, and not its actual functionality, since I don't intend for the functionality of that constructor to ever affect observable program behavior.

PK

Matthew Dempsky

unread,
Oct 22, 2014, 1:57:17 PM10/22/14
to Peter Kasting, James Robinson, hendrikw, Chromium-dev, Daniel Bratell, David Michael
Ping?

It seems contentious whether we should allow "= default" for the default constructor, and IMO it makes sense to disallow that use case: if A has any data members then the style guide requires explicit initialization for all of them anyway (which the default constructor won't do), and if it doesn't then "A() {}" is shorter than "A() = default" anyway (as jamesr@ points out).

However, the Google C++ style guide specifically encourages uses "= default" for copy constructors and operator= ("Prefer to define copy and move operations with = default.", where "copy operations" here means both copy constructor and copy-assignment operator) and that's much more convenient when writing simple value types composed of other value types.

Is there any opposition to allowing "= default" just for copy operations for now, and we can continue debating the merits in other cases?  Maybe we can at least hide them behind ALLOW_{COPY,ASSIGN,COPY_AND_ASSIGN}() macros so people don't have an need to directly write "= default" and so are less likely to accidentally use it in style-violating ways?

--

James Robinson

unread,
Oct 22, 2014, 2:02:50 PM10/22/14
to Matthew Dempsky, Peter Kasting, hendrikw, Chromium-dev, Daniel Bratell, David Michael
Having different rules for copy vs move that are different from the Google C++ style guide seems worse than having a simpler rule "don't use =default for constructors".  The most useful thing to advance this proposal would be to advance our toolchains.

- James

Alex Vakulenko

unread,
Oct 22, 2014, 2:15:22 PM10/22/14
to James Robinson, Matthew Dempsky, Peter Kasting, hendrikw, Chromium-dev, Daniel Bratell, David Michael
It's seems weird to me that we make a decision to ban a language feature just because "A() {}" is shorter to type compared to "A() = default;". And since custom user-provided default constructor "A() {}" will disable a bunch optimizations in the class compared to the case of compiler-provided default constructor which is important for copyable types. Using A() {} instead of A() = default; might be shorter to type but we loose:
  • Automatic move constructors.
  • 'noexcept' specifiers on the generated constructors which means that if you have a struct that contains some STL data like string, vector, map, etc and you have a vector of such structures, adding an element to the container might cause reallocation of the storage buffers and copying the data instead of moving it, since the constructor of the struct will no longer have 'noexcept' and the STL contructors use std::move_if_noexcept() internally.
So, even if we can't make use of move semantics ourselves as yet (since std::move is not accessible on all platforms), the STL code on libraries that do have C++11 features will automatically use it and our vectors and maps on these platforms will be faster.

Matthew Dempsky

unread,
Oct 22, 2014, 2:53:42 PM10/22/14
to James Robinson, Peter Kasting, hendrikw, Chromium-dev, Daniel Bratell, David Michael
On Wed, Oct 22, 2014 at 11:01 AM, James Robinson <jam...@chromium.org> wrote:
Having different rules for copy vs move that are different from the Google C++ style guide seems worse than having a simpler rule "don't use =default for constructors".

Considering that move semantics are currently banned in Chromium anyway, it seems like a non-issue whether Chromium style differs from Google style on being able to use "= default" with move operations, whereas having "= default" for copy operations is at least useful today.

Alex Vakulenko

unread,
Oct 22, 2014, 3:02:05 PM10/22/14
to Matthew Dempsky, James Robinson, Peter Kasting, hendrikw, Chromium-dev, Daniel Bratell, David Michael
Having move semantics banned doesn't mean that standard containers are not using it all over the place to optimize its functionality.

Having a simple struct like:

struct Data {
  std::vector<int> numbers;
  std::string name;
};

You will automatically have both a copy constructor and a move constructor for Data and it will be used heavily to optimize, say:

std::vector<Data> data;

If you want to add a custom constructor, you will also need to provide the default one, so the class is default-constructible:

struct Data {
  Data() = default;
  Data(const std::string& init_name) : name(init_name) {}

  std::vector<int> numbers;
  std::string name;
};

This still works fine and has both copy and move constructors. And std::vector<Data>  is nice and fact and will use move constructor of Data when growing a container.

But if you declare it as:

struct Data {
  Data() {}
  Data(const std::string& init_name) : name(init_name) {}

  std::vector<int> numbers;
  std::string name;
};

You suddenly lost your move semantics and now std::vector<Data> will have to copy all of the elements in the vector when it reallocates the storage.

Yes, you can't use explicit move semantics yet because of lack of library support on all platforms. But I don't understand why we should penalize the platform that do support it for at least standard containers...

Alex

--

Peter Kasting

unread,
Oct 22, 2014, 3:28:21 PM10/22/14
to James Robinson, Matthew Dempsky, hendrikw, Chromium-dev, Daniel Bratell, David Michael
On Wed, Oct 22, 2014 at 11:01 AM, James Robinson <jam...@chromium.org> wrote:
Having different rules for copy vs move that are different from the Google C++ style guide seems worse than having a simpler rule "don't use =default for constructors".  The most useful thing to advance this proposal would be to advance our toolchains.

It's not totally clear to me from above: do we actually have problems with =default when we're not writing explicit move constructors?  If not, given that move constructors are currently banned anyway, can we just use the standard Google style rules for =default?  I feel like most of the contention above is about cases that are actually miscompiled.

PK

Matthew Dempsky

unread,
Oct 22, 2014, 3:40:18 PM10/22/14
to Peter Kasting, James Robinson, hendrikw, Chromium-dev, Daniel Bratell, David Michael
On Wed, Oct 22, 2014 at 12:27 PM, Peter Kasting <pkas...@chromium.org> wrote:
It's not totally clear to me from above: do we actually have problems with =default when we're not writing explicit move constructors?  If not, given that move constructors are currently banned anyway, can we just use the standard Google style rules for =default?  I feel like most of the contention above is about cases that are actually miscompiled.

Hendrik reported earlier that MSVC simply rejects =default on move operations ("error C2610: 'A::A(A &&)' : is not a special member function which can be defaulted").

Thus the issue is that "A::A(A&&) = default" won't compile on Windows, but "A::A(A&&)" followed by anything is currently banned anyway in Chromium.  So I think it's a bad argument against allowing "= default" after "A::A(const A&)" or "A::operator=(const A&)", which is the Google C++ style guide's recommendation.

I don't really care about "A() {}" vs "A() = default" (and Alex's last post seems to have good points in favor of the latter, though I haven't fully digested it yet); I just want to stop having to implement and maintain copy operations myself when the compiler can trivially do it for me.

Nico Weber

unread,
Nov 5, 2014, 6:26:43 PM11/5/14
to Matthew Dempsky, Peter Kasting, James Robinson, hendrikw, Chromium-dev, Daniel Bratell, David Michael
Matthew explained to me that http://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Copyable_Movable_Types explicitly says that copyable types should have explicit copy constructors and assignment operators. Chromium code seems to apply to this rule pretty well, so allowing =default for this makes sense to me. I personally don't see a big advantage of `A() = default` over `A() {}`, but I don't think we need to let the guide make a recommendation on this. Matthew, can you send a CL to move =default (and =delete, while we're at it, I suppose) up to allowed?

Nico Weber

unread,
Nov 7, 2014, 12:28:22 AM11/7/14
to Matthew Dempsky, Peter Kasting, James Robinson, hendrikw, Chromium-dev, Daniel Bratell, David Michael
I don't really care about "A() {}" vs "A() = default" (and Alex's last post seems to have good points in favor of the latter, though I haven't fully digested it yet); I just want to stop having to implement and maintain copy operations myself when the compiler can trivially do it for me.

Matthew explained to me that http://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Copyable_Movable_Types explicitly says that copyable types should have explicit copy constructors and assignment operators. Chromium code seems to apply to this rule pretty well, so allowing =default for this makes sense to me. I personally don't see a big advantage of `A() = default` over `A() {}`, but I don't think we need to let the guide make a recommendation on this. Matthew, can you send a CL to move =default (and =delete, while we're at it, I suppose) up to allowed?

This is now allowed: http://chromium-cpp.appspot.com/
Reply all
Reply to author
Forward
0 new messages