std::unordered_map::operator[] - why there are two signatures? - c++

In the C++11, there are two versions of std::unordered_map::operator[], namely:
mapped_type& operator[] ( const key_type& k ); //1
mapped_type& operator[] ( key_type&& k ); //2
There are two questions:
1) Why the second one is necessary - the first one allows to pass constant to the function, since the first one contains the keyword const
2) For example, which version, 1 or 2, will be called in this case:
std::unordered_map<std::string, int> testmap;
testmap["test"] = 1;

Normally, the key is only used for comparison purposes, so you might wonder why rvalue semantics are necessary: a const reference should already cover that case.
But one thing to note is that operator[] can indeed create a new key/value pair: if the key wasn't already existent in the map.
In that case, if the second overload was used, then the map can safely move the provided key value in the map (while default initializing the value). It's a pretty rare and negligible optimization in my opinion, but when you're the C++ standard library, you shouldn't spare any efforts to save someone a cycle, even if it happens just once!
As for the second question, I might be wrong but it should consider the second overload as the best overload.
Edit:
There is also a valid point that it might allow you to use move-only objects as key values, even if it's a debatable decision

It's there for performance reasons. For example if the key is an rvalue, the key is moved instead of copied when a new element is inserted.
Thus, you avoid extra copy of an object/key. You can see this in the following example:
#include <iostream>
#include <unordered_map>
struct Foo {
Foo() { std::cout << "Foo() called" << std::endl; }
Foo(Foo const &other) { std::cout << "Foo(Foo const &other) called" << std::endl; }
Foo(Foo &&other) { std::cout << "Foo(Foo &&other) called" << std::endl; }
int i = 0;
};
bool operator==(Foo const &lhs, Foo const &rhs) {
return lhs.i == rhs.i;
}
void hash_combine(std::size_t& seed, const Foo& v) {
std::hash<int> hasher;
seed ^= hasher(v.i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
struct CustomHash {
std::size_t operator()(Foo const& v) const {
std::size_t res = 0;
hash_combine(res, v);
return res;
}
};
int main() {
std::unordered_map<Foo, int, CustomHash> fmap;
Foo a;
a.i = 100;
fmap[a] = 100;
fmap[Foo()] = 1;
}
LIVE DEMO
Output:
Foo() called
Foo(Foo const &other) called
Foo() called
Foo(Foo &&other) called
As can see in the case fmap[Foo()] = 1; the rvalue object is moved in contrast with statement fmap[a] = 100; where a copy constructor is called.

Related

Generic "sqr" function

I'm trying to figure out how to write "fully generic function" for sqr operation (it's actually can be multiply, division, add, does not really matter).
Consider the following code
#include <iostream>
struct A
{
int val = 2;
A() = default;
A(const A&) = delete; // To make sure we do not copy anything
A(A&& a) = delete; // To make sure we do not move anything
auto operator=(auto) = delete; // To make sure we do not assign anything
// This is important part, we do not want to create a new object on each multiplication.
// We want just to update the old one.
A& operator*(const A& a)
{
val *= a.val;
return *this;
}
};
// Just for easy printing (you can ignore it).
std::ostream &operator<<(std::ostream &os, const A& a) {
return os << a.val;
}
// Here auto&& represents forwarding reference and should automatically understand whether input r or l value.
auto&& sqr(auto&& val)
{
return val * val;
}
int main()
{
A a;
std::cout << sqr(a) << "\n"; // OK
std::cout << sqr(A()) << "\n"; // OK
std::cout << sqr(1) << "\n"; // Wrong, ref to local returned
int i = 2;
std::cout << sqr(i) << "\n"; // Wrong, ref to local returned
}
sqr function here is meant to be sort of generic stuff, it should handle all possible situations (r-values, l-values) and for object a it's actually does, but not for i. I can't get why it's trying to return reference instead of copy. Could anyone please shed some light on the situation? Is there any way I can accomplish this task easily (with one template function ideally)? I can use c++ 20 standard if necessary.
auto&& sqr(auto&& val)
{
return val * val;
}
sqr above always returns a reference. But returning a reference to a local is always wrong. Let the return-type deduce to a non-reference by using auto instead.
constexpr // May be constexpr for some types
auto sqr(auto&& x) // return type is non-reference or trailing
noexcept(noexcept(x*x)) // propagate noexcept
-> decltype(x*x) // enable SFINAE
{ return x * x; }

Is there a never-null unique owner of heap allocated objects?

Currently, I'm storing a collection of std::unique_ptrs to heap allocated objects of a polymorphic type:
struct Foo {
virtual ~Foo() = default;
};
Collection<std::unique_ptr<Foo>> foos;
The basic interface I need is putting / taking owners of Foo to / from foos. The objects stored in foos are never supposed to be nullptr so I'd like to replace runtime assert(owner_taken) with compile-time checks. Moreover, I would like to be capable of using non-null owners in the context where a nullable one may be expected.
Probably, I need to store something like unique_ref but how would I extract one from foos? I don't want a copy, I want the stored object itself, so owner->clone() isn't a solution. Neither I can std::move(owner) because the state of a "unique reference" would be invalid afterwards.
Is there a clean design decision?
Is there a never-null unique owner of heap allocated objects?
There is no such type in the standard library.
It is possible to implement such type. Simply define a type with unique_ptr member and mark the default constructor deleted. You can mark constructor from std::nullptr_t deleted also so that construction from nullptr will be prevented at compile time.
Whether you construct from an external pointer, or allocate in the constructor, there is no alternative for checking for null at runtime.
Reading your question, I interpret the following requirements:
You don't want to copy or move the object itself (Foo)
You don't want a wrapper which has some sort of empty state which excludes move semantics
The object itself (Foo) should be stored on the heap such that its lifetime is independent of the control flow
The object itself (Foo) should be deleted once it is not used any more
As construction / destruction, copy and move are the only ways to get objects into / out of a container, the only thing left is a wrapper object which is copied when moved into / out of the container.
You can create such an object yourself as follows:
// LICENSE: MIT
#include <memory>
#include <utility>
template<typename T>
class shared_ref {
public:
template<typename ...Args>
shared_ref(Args&&... args)
: data{new T(std::forward<Args>(args)...)}
{}
shared_ref(shared_ref&&) = delete;
shared_ref& operator=(shared_ref&&) = delete;
T& get() noexcept {
return *data;
}
const T& get() const noexcept {
return *data;
}
operator T&() noexcept {
return get();
}
operator const T&() const noexcept {
return get();
}
void swap(shared_ref& other) noexcept {
return data.swap(other);
}
private:
std::shared_ptr<T> data;
};
template<class T>
void swap(shared_ref<T>& lhs, shared_ref<T>& rhs) noexcept {
return lhs.swap(rhs);
}
I leave it as an exercise to the reader to add support for Allocator, Deleter, operator[], implicit conversion contructor to base classes.
This can then be used as follows:
#include <iostream>
int main() {
shared_ref<int> r; // default initialized
std::cout << "r=" << r << std::endl;
r = 5; // type conversion operator to reference
std::cout << "r=" << r << std::endl;
shared_ref<int> s{7}; // initialized with forwarded arguments
std::cout << "s=" << s << std::endl;
std::swap(r, s);
std::cout << "r=" << r << ", " << "s=" << s << std::endl;
s = r; // copy assignment operator
std::cout << "s=" << s << std::endl;
const shared_ref<int> t{s}; // copy constructor
std::cout << "t=" << t << std::endl;
//t = 8; // const ref from a const object is immutable
return 0;
}

Understanding and using a copy assignment constructor

I'm trying to understand how the copy assignment constructor works in c++. I've only worked with java so i'm really out of my waters here. I've read and seen that it's a good practice to return a reference but i don't get how i should do that. I wrote this small program to test the concept:
main.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main() {
Test t1,t2;
t1.setAge(10);
t1.setId('a');
t2.setAge(20);
t2.setId('b');
cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";
t2 = t1; // calls assignment operator, same as t2.operator=(t1)
cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";
Test t3 = t1; // copy constr, same as Test t3(t1)
cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";
return 1;
}
test.h:
class Test {
int age;
char id;
public:
Test(){};
Test(const Test& t); // copy
Test& operator=(const Test& obj); // copy assign
~Test();
void setAge(int a);
void setId(char i);
int getAge() const {return age;};
char getID() const {return id;};
};
test.cpp:
#include "test.h"
void Test::setAge(int a) {
age = a;
}
void Test::setId(char i) {
id = i;
}
Test::Test(const Test& t) {
age = t.getAge();
id = t.getID();
}
Test& Test::operator=(const Test& t) {
}
Test::~Test() {};
I can't seem to understand what i should be putting inside operator=(). I've seen people returning *this but that from what i read is just a reference to the object itself (on the left of the =), right? I then thought about returning a copy of the const Test& t object but then there would be no point to using this constructor right? What do i return and why?
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
How
Add
return *this;
as the last line in the function.
Test& Test::operator=(const Test& t) {
...
return *this;
}
Why
As to the question of why you should return *this, the answer is that it is idiomatic.
For fundamental types, you can use things like:
int i;
i = 10;
i = someFunction();
You can use them in a chain operation.
int j = i = someFunction();
You can use them in a conditional.
if ( (i = someFunction()) != 0 ) { /* Do something */ }
You can use them in a function call.
foo((i = someFunction());
They work because i = ... evaluates to a reference to i. It's idiomatic to keep that semantic even for user defined types. You should be able to use:
Test a;
Test b;
b = a = someFunctionThatReturnsTest();
if ( (a = omeFunctionThatReturnsTest()).getAge() > 20 ) { /* Do something */ }
But Then
More importantly, you should avoid writing a destructor, a copy constructor, and a copy assignment operator for the posted class. The compiler created implementations will be sufficient for Test.
We return a reference from the assignment operator so we can do some cool tricks like #SomeWittyUsername shows.
The object we want to return a reference to is the one who the operator is being called on, or this. So--like you've heard--you'll want to return *this.
So your assignment operator will probably look like:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
You may note that this looks strikingly similar to your copy-constructor. In more complicated classes, the assignment operator will do all the work of the copy-constructor, but in addition it'll have to safely remove any values the class was already storing.
Since this is a pretty simple class, we have nothing we need to safely remove. We can just re-assign both of the members. So this will be almost exactly the same as the copy-constructor.
Which means that we can actually simplify your constructor to just use the operator!
Test::Test(const Test& t) {
*this = t;
}
Again, while this works for your simple class, in production code with more complicated classes, we'll usually want to use initialization lists for our constructors (read here for more):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
Returning reference to the original object is needed for support of nested operations.
Consider
a = b = c

Can a const object, returned by value, still be moved?

Example:
Foo return_a_foo()
{
const auto a_foo = make_a_foo();
//Work with, but do not mutate a_foo...
return a_foo;
}
If the compiler cannot employ RVO, I'd at least expect it to try and move a_foo. However, a_foo is const (but still about to go out of scope). Does it say anywhere in the standard that this is 100% guaranteed not to move (bummer) or is it implementation defined ?
Can a const object, returned by value, still be moved?
Some will be shocked to learn that the answer is, "sometimes, yes".
However, you have to give them more constructors in order to enable this. You would also have to either make members mutable or otherwise manually handle const-move-construction.
Proof:
#include <iostream>
#include <memory>
struct Foo
{
Foo() { std::cout << "default c'tor\n"; }
Foo(Foo const&&) { std::cout << "Foo const&&\n"; }
Foo(Foo &&) { std::cout << "Foo &&\n"; }
Foo(Foo const&) { std::cout << "Foo const&\n"; }
Foo(Foo &) { std::cout << "Foo &\n"; }
};
const Foo make_a_foo()
{
auto p = std::make_unique<const Foo>();
return std::move(*p);
}
const Foo return_a_foo()
{
const auto a_foo = make_a_foo();
//Work with, but do not mutate a_foo...
return a_foo;
}
int main()
{
auto f = return_a_foo();
}
example output:
default c'tor
Foo const&&
No, a const T can't be bound to a non-const T&&, so a_foo can't be moved from.
Your function returns a non-const Foo though, so a_foo will be copied to the return value. The return value can then be moved from, since it's non-const. See this example.
In reality all of those copies and moves will likely be elided.

non-resizeable vector/array of non-reassignable but mutable members?

Is there a way to make a non-resizeable vector/array of non-reassignable but mutable members? The closest thing I can imagine is using a vector<T *> const copy constructed from a temporary, but since I know at initialization how many of and exactly what I want, I'd much rather have a block of objects than pointers. Is anything like what is shown below possible with std::vector or some more obscure boost, etc., template?
// Struct making vec<A> that cannot be resized or have contents reassigned.
struct B {
vector<A> va_; // <-- unknown modifiers or different template needed here
vector<A> va2_;
// All vector contents initialized on construction.
Foo(size_t n_foo) : va_(n_foo), va2_(5) { }
// Things I'd like allowed: altering contents, const_iterator and read access.
good_actions(size_t idx, int val) {
va_[idx].set(val);
cout << "vector<A> info - " << " size: " << va_.size() << ", max: "
<< va_.max_size() << ", capacity: " << va_.capacity() << ", empty?: "
<< va_.empty() << endl;
if (!va_.empty()) {
cout << "First (old): " << va_[0].get() << ", resetting ..." << endl;
va_[0].set(0);
}
int max = 0;
for (vector<A>::const_iterator i = va_.begin(); i != va_.end(); ++i) {
int n = i->get();
if (n > max) { max = n; }
if (n < 0) { i->set(0); }
}
cout << "Max : " << max << "." << endl;
}
// Everything here should fail at compile.
bad_actions(size_t idx, int val) {
va_[0] = va2_[0];
va_.at(1) = va2_.at(3);
va_.swap(va2_);
va_.erase(va_.begin());
va_.insert(va_.end(), va2_[0]);
va_.resize(1);
va_.clear();
// also: assign, reserve, push, pop, ..
}
};
There is an issue with your requirements. But first let's tackle the fixed size issue, it's called std::tr1::array<class T, size_t N> (if you know the size at compile time).
If you don't know it at compile time, you can still use some proxy class over a vector.
template <class T>
class MyVector
{
public:
explicit MyVector(size_t const n, T const& t = T()): mVector(n,t) {}
// Declare the methods you want here
// and just forward to mVector most of the time ;)
private:
std::vector<T> mVector;
};
However, what is the point of not being assignable if you are mutable ? There is nothing preventing the user to do the heavy work:
class Type
{
public:
int a() const { return a; }
void a(int i) { a = i; }
int b() const { return b; }
void b(int i) { b = i; }
private:
Type& operator=(Type const&);
int a, b;
};
Nothing prevents me from doing:
void assign(Type& lhs, Type const& rhs)
{
lhs.a(rhs.a());
lhs.b(rhs.b());
}
I just want to hit you on the head for complicating my life...
Perhaps could you describe more precisely what you want to do, do you wish to restrict the subset of possible operations on your class (some variables should not be possible to modify, but other could) ?
In this case, you could once again use a Proxy class
class Proxy
{
public:
// WARN: syntax is screwed, but `vector` requires a model
// of the Assignable concept so this operation NEED be defined...
Proxy& operator=(Proxy const& rhs)
{
mType.a = rhs.mType.a;
// mType.b is unchanged
return *this;
}
int a() const { return mType.a(); }
void a(int i) { mType.a(i); }
int b() const { return mType.b(); }
private:
Type mType;
};
There is not much you cannot do with suitable proxies. That's perhaps the most useful pattern I have ever seen.
What you're asking is not really possible.
The only way to prevent something from being assigned is to define the operator = for that type as private. (As an extension of this, since const operator = methods don't make much sense (and are thus uncommon) you can come close to this by only allowing access to const references from your container. But the user can still define a const operator =, and you want mutable objects anyways.)
If you think about it, std::vector::operator [] returns a reference to the value it contains. Using the assignment operator will call operator = for the value. std::vector is completely bypassed here (except for the operator[] call used to get the reference in the first place) so there is no possibility for it (std::vector) to in any way to override the call to the operator = function.
Anything you do to directly access the members of an object in the container is going to have to return a reference to the object, which can then be used to call the object's operator =. So, there is no way a container can prevent objects inside of it from being assigned unless the container implements a proxy for the objects it contains which has a private assignment operator that does nothing and forwards other calls to the "real" object, but does not allow direct access to the real object (though if it made sense to do so, you could return copies of the real object).
Could you create a class which holds a reference to your object, but its constructors are only accessible to its std::vector's friend?
e.g.:
template<typename T>
class MyRef {
firend class std::vector< MyRef<T> >
public:
T& operator->();
[...etc...]
You can achieve what you want by making the std::vector const, and the vector's struct or class data mutable. Your set method would have to be const. Here's an example that works as expected with g++:
#include <vector>
class foo
{
public:
foo () : n_ () {}
void set(int n) const { n_ = n; }
private:
mutable int n_;
};
int main()
{
std::vector<foo> const a(3); // Notice the "const".
std::vector<foo> b(1);
// Executes!
a[0].set(1);
// Failes to compile!
a.swap(b);
}
That way you can't alter the vector in any way but you can modify the mutable data members of the objects held by the vector. Here's how this example compiles:
g++ foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:24: error: passing 'const std::vector<foo, std::allocator<foo> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::swap(std::vector<_Tp, _Alloc>&) [with _Tp = foo, _Alloc = std::allocator<foo>]' discards qualifiers
The one disadvantage I can think of is that you'll have to be more aware of the const-correctness of your code, but that's not necessarily a disadvantage either.
HTH!
EDIT / Clarification: The goal of this approach is not defeat const completely. Rather, the goal is to demonstrate a means of achieving the requirements set forth in the OP's question using standard C++ and the STL. It is not the ideal solution since it exposes a const method that allows alteration of the internal state visible to the user. Certainly that is a problem with this approach.