1

The following program works without error.

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
class userContext {
public:
    int id;
    int value1;
    int value2;
    userContext():id(-1),value1(-1),value2(-1){}
    userContext(userContext &context) {
        this->id = context.id;
        this->value1 = context.value1;
        this->value2 = context.value2;
    }
};
int main() {
    userContext a;
    a.id = 1;
    a.value1 = 2;
    a.value2 = 3;
    // map<int,userContext> Map;
    // Map[1] = a;
    cout << a.value1 << endl;
    cout << a.value2 << endl;
    return 0;
}

But If I introduce a map, it gives an error. Why is it so?

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
class userContext {
public:
    int id;
    int value1;
    int value2;
    userContext():id(-1),value1(-1),value2(-1){}
    userContext(userContext &context) {
        this->id = context.id;
        this->value1 = context.value1;
        this->value2 = context.value2;
    }
};
int main() {
    userContext a;
    a.id = 1;
    a.value1 = 2;
    a.value2 = 3;
    map<int,userContext> Map;
    Map[1] = a;
    cout << Map[1].value1 << endl;
    cout << Map[1].value2 << endl;
    return 0;
}

part of compilation error output:

locks.cpp:20:7:   required from here
/usr/include/c++/7/bits/stl_pair.h:292:17: error: ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = userContext]’ declared to take const reference, but implicit declaration would take non-const
       constexpr pair(const pair&) = default;

However, changing copy constructor signature to userContext(const userContext &context) resolves the compilation error and programs executes fine. Please explain.

Thanks!

Debashish
  • 1,155
  • 19
  • 34
  • 3
    `#include ` [Don't do this](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h?lq=1). Your program is uncompilable on the platform that I would test on. – PaulMcKenzie Dec 21 '18 at 10:32
  • 1
    In addition, your copy constructor has a flaw in that it fails to copy the `id` member. So now you have fake copies being generated. – PaulMcKenzie Dec 21 '18 at 10:36
  • 4
    Your question is sort of a duplicate of [Why C++ copy constructor must use const object?](https://stackoverflow.com/questions/16956693/why-c-copy-constructor-must-use-const-object), but the answer to your question would be to remove your copy constructor implementation and let the compiler generate the default one for you. – jxh Dec 21 '18 at 10:39
  • @PaulMcKenzie , yes corrected ! – Debashish Dec 21 '18 at 10:40
  • @DanielLangr my comment didn't bring anything that was not already said, hence removed, but still standard copy constructor would be const&. – Matthieu Brucher Dec 21 '18 at 10:41
  • 1
    @Debashish _Please explain._ This might help: https://stackoverflow.com/a/43607151/580083. – Daniel Langr Dec 21 '18 at 10:51
  • 1
    @MatthieuBrucher Agree, but it would be good to explain why `std::map` requires its mapped type to require such a _standard copy constructor_ (edit: Bathsheba just did it in his answer). – Daniel Langr Dec 21 '18 at 10:53

1 Answers1

4

A copy constructor that does not pass the copied object by const reference does not satisfy the requirements of an AllocatorAwareContainer which is one of the concepts requried by a std::map.

In the absence of your passing in an alternative allocator on the std::map construction, compilation will fail.

Reference: https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer

Bathsheba
  • 231,907
  • 34
  • 361
  • 483