lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Various C++ m12ns


From: Greg Chicares
Subject: Re: [lmi] Various C++ m12ns
Date: Mon, 6 Mar 2017 22:28:53 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0

On 2017-02-01 21:58, Vadim Zeitlin wrote:
> On Wed, 1 Feb 2017 21:47:34 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> Vadim, what do you think about...
> GC> 
> GC> (1) Changing '> >' to '>>' to close template-parameter-lists?
[...]
> So yes, I'd definitely remove the
> spaces, if only because there is no reason to have them in the new code and
> consistency is good.

Done:

commit ba9c81247a467ed242d821e47b17c6acc8b5c738
    Remove stray spaces in template instantiations

> GC> (2) Replacing
> GC> 
> GC>   class foo : private lmi::uncopyable<foo>
> GC> 
> GC> with
> GC> 
> GC>   class foo
> GC>   ...
> GC>       foo(foo const&) = delete;
> GC>       foo& operator=(foo const&) = delete;
> GC> 
> GC> ? I'm not convinced that such a change should be made. If C++11 let us
> GC> write it the way we can write 'final':
> GC>   class foo : uncopyable
> GC> then that would be best. But declaring two extra member functions
> GC> requires writing the class's name four times, and typically those
> GC> declarations would be somewhere in the middle of the class declaration,
> GC> after public members and before other private members. It just seems
> GC> more verbose and less readable to me.

Looking back--over the last few days I've done this in about 175 files,
and I didn't delete the header name manually 175 times, much less write a
class name 700 times. Instead, I did it once with

  sed -e'/include.*uncopyable_lmi.hpp/d'
  sed -e'/lmi::uncopyable/s/^.*lmi::uncopyable *< *\(.*\) *>.*$/&\n    \1(\1 
const\&) = delete;\n    \1\& operator=(\1 const\&) = delete;\n/

and then separately, in another directory, with a couple of vim macros,
watching what the macros did carefully and making some layout changes.
Then, after cleaning up the sed work manually, and testing both separately,
I compared them and resolved the differences, which were few and slight.
This would have been unpleasant with less capable tools.

>  I understand this point of view, but I don't agree with it mainly because
> I have a rule, predating C++11, consisting in always doing something about
> the compiler-generated functions because forgetting to do it is so common
> in C++ code, that it's very nice to have an explicit reminder that the
> author did think about it. So even if the default behaviour is appropriate,
> I would always write a comment like this
> 
>       // Compiler-generated copy ctor and assignment operator are ok.

Me too:

/srv/chroot/cross-lmi/opt/lmi/src/lmi[0]$grep 'Implicitly-declared special 
member functions do the right thing' *.?pp |wc -l   
47

> in C++98 code. And in C++11 code I use
> 
>       foo(foo const&) = default;
>       foo& operator=(foo const&) = default;
> 
> to say this in code instead of comments. So from my point of view, it's
> natural to have the same with "= delete" if the compiler-generated
> functions are not appropriate and, in fact, jarring not to see these 2
> lines in the code.
> 
>  This is, of course, a question of habit, but I believe it's a good habit
> to have.

Thanks for saying this. I found some special member functions with full
implementations that were purely redundant, so, instead of eradicating
them utterly as was my first impulse, I kept the declarations (only):

commit 6234aec54070cf4c596e10ee00ccfe51328671e0

    Replace copy functions with explicitly-defaulted equivalents
    
    The removed implementations of the copy ctor and assignment operator
    were equivalent to those the compiler would have written anyway. Their
    declarations were retained with explicit '= default' as documentation.

Let's see if we can write a guideline for this....

Declare these special member functions by default in every class X:
    X(X const&) = delete;
    X& operator=(X const&) = delete;
If X should be Copyable, then use '= default' instead. Write implementations
in '{}' only if the default does not do the right thing.

Rationale: In C++98, a comment such as
  Implicitly-declared special member functions do the right thing
was appropriate, with the declarations elided. But in C++11, it is
preferable to say that in code. This is better than deriving from
a noncopyable class because it is clearer and optimizes better.

Already I have a question about the guideline. Would you also
always declare a destructor, with '= default' by default?

And another question. At first I was going to recommend either
  public:
    X(X const&) = default;
    X& operator=(X const&) = default;
or
  private:
    X(X const&) = delete;
    X& operator=(X const&) = delete;
but then I figured that calling a deleted public function ought
to produce as clear a diagnostic as calling a deleted private one;
so I think it's okay to declare these preferably in the neighborhood
of other special-member-function declarations, but that seems to
require no guideline. A private '= delete' declaration is never wrong,
and I won't move the ones I've already written, but in the future I'd
probably write all special member functions together in the typical
case.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]