2

I have a problem using 'emplace_back' on an instance of a class with const members.

See a sample code listing below.

#include <vector>
using std::vector;

class Data {
  public:
    Data(int a, int b, int c) : a(a), b(b), c(c) {}

    // Removing any/all of these constructors changes nothing!
    Data& operator=(const Data& s) = default;
    Data(const Data& s) = default;
    Data(Data&& s) = default;
    ~Data() = default;

    const int a;
    const int b;
    const int c;
};


int main() {
  vector<Data> v;
  Data e(1,2,3);

  // Problem line
  v.emplace_back(4,5,6);
}

The compilation error:

% clang++ a.cc  -std=c++11

In file included from a.cc:1:
In file included from /usr/include/c++/4.6/vector:69:
/usr/include/c++/4.6/bits/vector.tcc:319:16: error: overload resolution selected
      deleted operator '='
          *__position = _Tp(std::forward<_Args>(__args)...);
          ~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/4.6/bits/vector.tcc:102:4: note: in instantiation of function
      template specialization 'std::vector<Data, std::allocator<Data>
      >::_M_insert_aux<int, int, int>' requested here
          _M_insert_aux(end(), std::forward<_Args>(__args)...);
          ^
a.cc:25:5: note: in instantiation of function template specialization
      'std::vector<Data, std::allocator<Data> >::emplace_back<int, int, int>'
      requested here
  v.emplace_back(4,5,6);
    ^
a.cc:9:11: note: candidate function has been explicitly deleted
    Data& operator=(const Data& s) = default;
          ^
In file included from a.cc:1:
In file included from /usr/include/c++/4.6/vector:60:
/usr/include/c++/4.6/bits/stl_algobase.h:546:18: error: overload resolution
      selected deleted operator '='
            *--__result = std::move(*--__last);
            ~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/4.6/bits/stl_algobase.h:578:14: note: in instantiation of
      function template specialization 'std::__copy_move_backward<true, false,
      std::random_access_iterator_tag>::__copy_move_b<Data *, Data *>' requested
      here
      return std::__copy_move_backward<_IsMove, __simple,
             ^
/usr/include/c++/4.6/bits/stl_algobase.h:588:19: note: in instantiation of
      function template specialization 'std::__copy_move_backward_a<true, Data
      *, Data *>' requested here
      return _BI2(std::__copy_move_backward_a<_IsMove>
                  ^
/usr/include/c++/4.6/bits/stl_algobase.h:659:14: note: in instantiation of
      function template specialization 'std::__copy_move_backward_a2<true, Data
      *, Data *>' requested here
      return std::__copy_move_backward_a2<true>(std::__miter_base(__first),
             ^
/usr/include/c++/4.6/bits/vector.tcc:313:4: note: in instantiation of function
      template specialization 'std::move_backward<Data *, Data *>' requested
      here
          _GLIBCXX_MOVE_BACKWARD3(__position.base(),
          ^
/usr/include/c++/4.6/bits/stl_algobase.h:664:48: note: expanded from:
#define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::move_backward(_Tp, _Up, _Vp)
                                               ^
/usr/include/c++/4.6/bits/vector.tcc:102:4: note: in instantiation of function
      template specialization 'std::vector<Data, std::allocator<Data>
      >::_M_insert_aux<int, int, int>' requested here
          _M_insert_aux(end(), std::forward<_Args>(__args)...);
          ^
a.cc:25:5: note: in instantiation of function template specialization
      'std::vector<Data, std::allocator<Data> >::emplace_back<int, int, int>'
      requested here
  v.emplace_back(4,5,6);
    ^
a.cc:9:11: note: candidate function has been explicitly deleted
    Data& operator=(const Data& s) = default;
          ^
2 errors generated.

Seeing this error message:

a.cc:9:11: note: candidate function has been explicitly deleted
        Data& operator=(const Data& s) = default;

I tried defining an assignment operator (and move and copy constructors, and a destructor) to make sure that the implicitly generated ones do not somehow become private. That did not change anything. I do not see why the assignment operator is "explicitly deleted" in this case case.

Note that changing the class members to be non-const results in no compilation errors.

WaelJ
  • 2,942
  • 4
  • 22
  • 28
  • 1
    Note: const (or reference, for that matter) members cannot be changed, making it difficult to impossible to write copy/move assignment or move constructors, including the compiler generated ones. – Nevin Mar 28 '14 at 17:34
  • Yes that does makes sense. However, I don't understand why a copy constructor is not allowed for a class with const members? See the error message in the middle `a.cc:9:11: note: candidate function has been explicitly deleted:Data& operator=(const Data& s) = default;` – WaelJ Mar 29 '14 at 12:37

1 Answers1

4

What is your clang version, your code is fine with clang and gcc.

Of course, it is not possible to default the operator= as it would fail to update the const members, but vector require only MoveConstructible/CopyConstructible and do not use operator= and your code is legal.

David G
  • 94,763
  • 41
  • 167
  • 253
galop1n
  • 8,573
  • 22
  • 36
  • I have Ubuntu clang version 3.0-6ubuntu3 – WaelJ Mar 28 '14 at 17:36
  • I downloaded clang 3.4 binary, and I get the same error messages (with or without the constructor/operator definitions). – WaelJ Mar 29 '14 at 12:36
  • clang is only a compiler, if it was outdated, your standard library (libc++ or libstdc++)and gcc ( for ld ) are likely to update too. – galop1n Mar 29 '14 at 12:38
  • I updated gcc to version 4.8 and installed libstdc++6. That did not seem to affect anything – WaelJ Mar 30 '14 at 13:51
  • 1
    Had to update g++ as well (of course!). Works as expected now, thanks :) – WaelJ Mar 30 '14 at 15:15