jeudi 3 décembre 2020

When and why are move contructors implicitly deleted?

The following code...

// main.cpp
#include <grpcpp/grpcpp.h>

class ClientContextContainer {
public:
  ClientContextContainer( int i ) : i_(i) {}

private:
  grpc::ClientContext client_context_;
  int i_;
};

class ArrayContainer {
public:
  ArrayContainer() : ccc_{ {42}, {1138} } {}

private:
  ClientContextContainer ccc_[2];
};

int main( int argc, char* argv[] ) {
  ArrayContainer ac;

 return 0;
}

...generates this error:

root@178258c7c52d:/tmp# /usr/bin/x86_64-linux-gnu-g++ --version && /usr/bin/x86_64-linux-gnu-g++ -c ./main.cpp
x86_64-linux-gnu-g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

./main.cpp: In constructor 'ArrayContainer::ArrayContainer()':
./main.cpp:15:41: error: use of deleted function 'ClientContextContainer::ClientContextContainer(ClientContextContainer&&)'
   ArrayContainer() : ccc_{ {42}, {1138} } {}
                                         ^
./main.cpp:4:7: note: 'ClientContextContainer::ClientContextContainer(ClientContextContainer&&)' is implicitly deleted because the default definition would be ill-formed:
 class ClientContextContainer {
       ^~~~~~~~~~~~~~~~~~~~~~
./main.cpp:4:7: error: 'grpc::ClientContext::ClientContext(const grpc::ClientContext&)' is private within this context
In file included from /usr/local/include/grpcpp/client_context.h:37,
                 from /usr/local/include/grpcpp/grpcpp.h:53,
                 from ./main.cpp:2:
/usr/local/include/grpcpp/impl/codegen/client_context.h:388:3: note: declared private here
   ClientContext(const ClientContext&);
   ^~~~~~~~~~~~~

I do not fully understand the compiler error, but by my reading, it implies that the problem is that class ClientContextContainer's move constructor is implicitly deleted because the class' member grpc::ClientContext object has a private copy constructor. (Inspection of client_context.h shows that its assignment operator is also private).

Fine. But if that's the case, why can't I reproduce the compile error if I replace the grpc::ClientContext member object with my own object that also has a private copy constructor (and assignment operator)?

// main.cpp
//#include <grpcpp/grpcpp.h>

class FauxClientContext {
public:
  FauxClientContext() {}

private:
  FauxClientContext( const FauxClientContext& );
  FauxClientContext& operator=( const FauxClientContext& );
};

class ClientContextContainer {
public:
  ClientContextContainer( int i ) : i_(i) {}

private:
  FauxClientContext client_context_;
  //grpc::ClientContext client_context_;
  int i_;
};

class ArrayContainer {
public:
  ArrayContainer() : ccc_{ {42}, {1138} } {}

private:
  ClientContextContainer ccc_[2];
};

int main( int argc, char* argv[] ) {
  ArrayContainer ac;

 return 0;
}
root@178258c7c52d:/tmp# /usr/bin/x86_64-linux-gnu-g++ --version && /usr/bin/x86_64-linux-gnu-g++ -c ./main.cpp
x86_64-linux-gnu-g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

root@178258c7c52d:/tmp#

What's the true nature of the error compiling the first version of main.cpp? That I could successfuly compile the second version of main.cpp implies that it's not what I interpreted the compiler error message to mean.


To those familiar with grpc, the root of this line of inquiry is: is it possible to construct an array of objects, in an initializer-list, if the objects have a member grpc::ClientContext object?

Aucun commentaire:

Enregistrer un commentaire