简体   繁体   中英

error: implicitly deleted because the default definition would be ill-formed (vector of structs)

I'm having trouble getting my C++ program to compile. Would really appreciate some help with this error. In the header file, I have this:

struct workerT{
 workerT() : status(true), threadSem(0){}
 bool status;
 std::function<void(void)> func;
 semaphore threadSem;
};

std::vector<workerT> workers;

In my .cc file, I am trying to initialize that vector like this:

fill(workers.begin(), workers.end(), workerT());

This fails with the error: error: 'TP::workerT& TP::workerT::operator=(const TP::workerT&)' is implicitly deleted because the default definition would be ill-formed: It points to the semaphore.h file. Semaphore.h is defined like this:

 public:
  semaphore(int value = 0);
  ....

private:
  int value;
  ....
  semaphore(const semaphore& orig) = delete;
  const semaphore& operator=(const semaphore& rhs) const = delete;

The program compiles if I remove the "fill" line, but I really need that because I want to initialize the vector. I get the same error message when I make a dummy struct and try to push_back into the vector.

Update: thanks @DyP! I still need help compiling. Replaced the "fill" line with this:

std::generate(workers.begin(), workers.end(), free_func);

Added exactly this to my header:

workerT free_func(){
 return {};
}

Getting these errors:

thread-pool.cc: In constructor 'ThreadPool::ThreadPool(size_t)': thread-pool.cc:33:58: error: argument of type 'ThreadPool::workerT (ThreadPool::)()' does not match 'ThreadPool::workerT (ThreadPool::*)()' In file included from /usr/include/c++/4.6/algorithm:63:0, from thread-pool.cc:15: /usr/include/c++/4.6/bits/stl_algo.h: In function 'void std::generate(_FIter, _FIter, _Generator) [with _FIter = __gnu_cxx::__normal_iterator >, _Generator = ThreadPool::workerT (ThreadPool::*)()]': thread-pool.cc:33:58: instantiated from here /usr/include/c++/4.6/bits/stl_algo.h:5013:2: error: must use '. ' or '-> ' to call pointer-to-member function in '__gen (...)', eg '(... ->* __gen) (...)' make: * [thread-pool.o] Error 1

Update-- In my .cc file:

 using namespace std;

 static workerT free_func(){
   return {};
 }

 ThreadPool(...args...){
   std::generate(workers.begin(), workers.end(), free_func);
 }

Errors:

thread-pool.cc:19:10: error: ‘workerT’ does not name a type
thread-pool.cc: In constructor ‘ThreadPool::ThreadPool(size_t)’:
thread-pool.cc:39:49: error: ‘free_func’ was not declared in this scope
make: *** [thread-pool.o] Error 1

Update again:

 static ThreadPool::workerT free_func(){
    return {};
 }

 ThreadPool(...args...){
   std::generate(workers.begin(), workers.end(), free_func);
 }

In thread-pool.h:

 struct workerT{
 workerT() : status(true), threadSem(0){}
 bool status;
 std::function<void(void)> func;
 semaphore threadSem;
};

As 0x499602d2 correctly pointed out, fill needs to copy-assign from the third argument. As your type implicitly is noncopyable, you cannot use fill .

You could, however, use generate to fill your vector:

#include <vector>
#include <algorithm>

struct noncopyable
{
    noncopyable() = default;

    // make it noncopyable
    noncopyable(noncopyable const&) = delete;
    noncopyable& operator=(noncopyable const&) = delete;

    // make it movable (thanks, gx_)
    noncopyable(noncopyable&&) = default;
    noncopyable& operator=(noncopyable&&) = default;
};

int main()
{
    std::vector<noncopyable> vec(10);
    std::generate(begin(vec), end(vec), []()->noncopyable{return {};});
}

Note: this only works if noncopyable has a non-deleted, accessible move constructor. However, if it does not have such a ctor, you won't be able to use much of the vector ( resize requires MoveInsertable , which requires either a copy- or move-ctor).


For g++4.8, to use generate , you'll need a free function. I think that's a bug.

#include <vector>
#include <algorithm>

struct noncopyable
{
    noncopyable() = default;
    noncopyable(noncopyable const&) = delete;
};

noncopyable free_func()
{  return {};  }

int main()
{
    std::vector<noncopyable> vec;
    std::generate(begin(vec), end(vec), free_func);
}

Yet another question is if you can initialize your vector like that. I'd say NO. fill and generate do not construct elements, but overwrite (assign). That is, you'll already need to have a vector with multiple elements before you can use them.

The easiest version to initialize a vector with N default-constructed elements is to use the constructor:

std::vector<noncopyable> vec(10);

Creates a vector with 10 default-constructed elements. The only requirement is that noncopyable is DefaultConstructible (essentially, it must have a default constructor).


If your type is noncopyable AND nonmovable, you cannot use it directly (or as a data member) to store it inside a vector (*). To make a class C movable, which contains a noncopyable, nonmovable type X , you need to store X as a pointer:

(*) Well, you can, but you cannot resize the vector, you cannot insert etc.

struct nocopies_nomoves
{
    nocopies_nomoves() = default;

    nocopies_nomoves(nocopies_nomoves const&) = delete;
    nocopies_nomoves& operator=(nocopies_nomoves const&) = delete;

    // not required to be explicitly deleted:
    nocopies_nomoves(nocopies_nomoves&&) = delete;
    nocopies_nomoves& operator=(nocopies_nomoves&&) = delete;
};

#include <utility>
#include <memory>
class C
{
public:
    C() : ptr( new nocopies_nomoves() ) {} // make_unique in C++1y

    // I don't think you need to explicitly define those as defaulted;
    // at least not if you don't declare ANY of the copy/move ctors, assignment ops
    // and dtor
    C(C&& rhs) = default;
    C& operator=(C&& rhs) = default;
    ~C() = default;

    // not required to be explicitly deleted:
    C(C const&) = delete;
    C& operator=(C const&) = delete;
private:
    std::unique_ptr<nocopies_nomoves> ptr;
};

Now you can create a vector<C> and use it (eg resize , insert , ...)

#include <vector>
#include <algorithm>

static C generate_C()
{
    return {};
}

int main()
{
    std::vector<C> vec(10);
    // note: futile statement below; overwrites the 10 default-constructed
    //       elements
    std::generate(begin(vec), end(vec), generate_C);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM