unordered_set using hash of value object's address - c++

I have a class which needs to have a std::unordered_set which holds non-copyable, non-moveable entity objects, and whose hash function hashes the instance's address. Something like the following:
class A
{
public:
A();
A(const A&) = delete;
A(A&&) = delete;
void operator=(const A&) = delete;
void operator=(A&&) = delete;
bool operator==(const A& other) { return this == &other; }
};
template<>
struct std::hash<A>
{
size_t operator()(const A& obj) const
{
return std::hash<A*>()(&obj);
}
};
class B
{
private:
std::unordered_set<A> entities;
};
If emplace() is always used instead of insert(), is it safe to use unordered_set in this way? Does the standard specify that an implementation can't move node objects after they are constructed?
What about if A were moveable? Is it guaranteed that the hash function will be called on the object owned by the set, or since the standard library prefers to think of everything as value-objects, is it allowed to hash an inserted object before storage is allocated for it?
As a final thought, I know I could get around all this by using std::unordered_set<std::unique_ptr<A>>, but I'd like to use a custom allocator for the A objects, and I don't want to override new and delete for A.

Using the address of an object as a hash pretty much guarantees that you won't find the object unless you already hold a pointer to the object other than iteration through the hash. You'll need to come up with a different approach to get a hash from your object. That said, once consructed inside the hash the object's address won't change.

I still think you are better off using a std::list. Consider:
#include <iostream>
#include <list>
class A
{
public:
int i_;
A(int i) : i_(i) {}
A(const A&) = delete;
A(A&&) = delete;
void operator=(const A&) = delete;
void operator=(A&&) = delete;
};
int main()
{
std::list< A > l;
// inserting elements
auto it1 = l.emplace( l.end(), 1 ); // note: complexity is O(1)
auto it2 = l.emplace( l.end(), 2 );
auto it3 = l.emplace( l.end(), 3 );
auto it4 = l.emplace( l.end(), 4 );
// deleting an element by iterator
l.erase( it2 ); // note: complexity is O(1)
// note: it2 is now invalid
// accessing element by iterator
it3->i_ = 42;
for( const auto& e : l ) {
std::cout << e.i_ << std::endl;
}
// silence compiler warnings
(void)it1;
(void)it4;
}
In the above, all your use-cases should have an efficient implementation. You can avoid the overhead of calculating the hash and having the hash-map. It's even more efficient as your hash-based approach, for the list both operations are O(1) and much more light-weigth wrt the implementation. And storing the iterator is not much different from storing a pointer to the element directly.
Also, it is guaranteed that this works for non-copyable and non-movable types. See the documentation for std::list::emplace.

As Dietmar mentions, once constructed, the value's address can't change. As far as the second part of the question, the standard seems to not only allow, but require implementations to call the hash/equal_to functors on an object passed to insert() by reference, rather than requiring the construction of a node first and calling the functions on that object:
From 23.2.5 Table 103 — Unordered associative container requirements
pair<iterator, bool> a_uniq.insert(t)
Effects: Inserts t if and only if there is no element in the container with key equivalent to the key of t.

Related

C++ iterator to initialize collections of objects with no default constructor

I have a class Foo with no sensible default constructor. I would also prefer to keep the copy-assignment operator private, although that may become impossible. (I'd like to make the class “almost” immutable, whence thread-safe, by having const fields and the small number of mutators that cast const way as private and early in the object lifetime.)
Creating std::vector<Foo> under these constraints is a little bit of a challenge. I came up with a solution I haven't seen elsewhere (see, for example, earlier SO question 1). I have a custom iterator which, when dereferenced, creates a Foo. It is set up such that each invocation increments to the next value of Foo in the vector. The sequence is easy to define. I define operator++, next, advance, distance and operator* on CustomIterator.
Then I have
std::vector<Foo> foo_vec{CustomIterator(0), CustomIterator(size_of_vector)};
No access issues. No unnecessary constructions. No copies. Anyone see a problem with this?
I will summarize the comments. The simple factory generates vector of initialized elements.
#include <vector>
class X {
explicit X(int value) : value_(value) {}
X& operator=(const X&) = default;
friend std::vector<X> generate(int from, int to);
public:
const int value_;
};
// simplest factory ever
std::vector<X> generate(int from, int to) {
std::vector<X> result;
result.reserve(to - from);
for (int k = from; k < to; ++k) {
result.emplace_back(std::move(X(k)));
}
return std::vector<X>();
}
int main() {
auto v = generate(0, 10);
static_cast<void>(v);
}

Overriding assignment operators in proxy class for vector object in a matrix?

I have a slight problem. I have a Matrix class defined as follows (in row-major form):
template<typename T>
class Matrix {
private:
class RowVector {
private:
T *_vec;
std::size_t _l;
public:
RowVector(T *vec, std::size_t l);
const T &operator[](std::size_t index) const;
T &operator[](std::size_t index);
operator std::vector<T>() const;
};
std::vector<T> _data;
std::size_t _m;
std::size_t _n;
public:
Matrix(std::size_t m, size_t n, const T &elem = T());
const RowVector operator[](std::size_t index) const;
RowVector operator[](std::size_t index);
std::size_t getm() const;
std::size_t getn() const;
void fill(const T &elem);
void fillRow(std::size_t index, const T &elem);
void fillCol(std::size_t index, const T &elem);
Matrix &transpose(unsigned int i = 1);
const std::vector<T> &data() const;
};
and wish to overload two RowVector operators=
typename Matrix<T>::RowVector &operator=(const std::vector<T> &vec);
typename Matrix<T>::RowVector &operator=(const Matrix<T> &mat);
so I can return a RowVector & using A[0] and reassign its value using either a vector or a matrix. Keep in mind that I (presumably) can ignore the rule of three because I provide no explicit way for the client to construct a RowVector object.
However, in attempting to write the function bodies for the overloads, I have come across a problem: that
(1) I cannot copy-construct a vector/Matrix object that will persist outside of the operator='s scope so that I can assign its data() to _vec and its size() to _l.
(2) I cannot directly modify _data since it is not a static variable; even if I could, I have no way to discover the index so I can overwrite the relevant region of memory in the enclosing Matrix object.
Do you know of any way in which this can be done? These would be two very useful assets for my class.
I would like to be able to write something like this:
Matrix<int> A(3, 4);
std::vector<int> v {1, 2, 3, 4};
Matrix<int> row(1, 4, 3);
// *****************
A[0] = v;
A[1] = row;
// *****************
(Hopefully my variable names are self-explanatory)
I think my prototypes are correct, but I just can't find a way to do this.
Thanks!
T *_vec;
std::size_t _l;
This is a problematic design! I don't say it is incorrect per se, but you then need to correctly manage the memory yourself. Ignoring the rule of three (five) is a very dangerous in this respect. You have a pointer to (potentially?) dynamically allocated memory, so there must be some instance that is responsible for its deletion (must not necessarily be your RowVector, but what else then?).
From pure technical aspect, you even can let _vec point to some vector's data, provided you gurantee that this other vector lives as long as you want to access the data via pointer – which in general requires, though, quite some effort.
Safest would be having each row maintain its own data, copying (or moving) it from the other vector. Then easiest is storing the data in a std::vector of its own (replacing the raw pointer).
If you want to avoid copying data around and instead share data between different matrices and their rows, then you could maintain the data via a std::shared_ptr - either maintaining a raw array or possibly even a heap-allocated std::vector.
If you opt for either std::vector or std::shared_ptr, then copy and move constructors and assignment operators get totally simple:
class C
{
public:
C(C const&) = default;
C(C&&) = default;
C& operator= (C const&) = default;
C& operator= (C&&) = default;
};
All of these defaults will do copying/moving as per member, and both std::vector and std::shared_ptr have the appropriate constructors and operators available already, so you'd be fine – and you now can violate the rule of five, dropping the destructor, as the default one (calling all the member's destructors) suffices.
If you consider shared pointers: be aware that you then cannot assign a std::vector's data to: std::vector does its own memory management, and you will end up in double deletion of, so in this specific case, you'd still have to create a copy of. You might possibly end up in multiple constructors and assignment operators:
std::shared_ptr<std::vector<int>> _data;
// assign shared pointers
RowVector(RowVector const&) = default;
RowVector(RowVector&&) = default;
// need to create copies of: we never know about the scope of the vector passed!
RowVector(std::vector<int> const& data) : _data(new std::vector<int>(data)) { }
RowVector(std::vector<int>&& data) : _data(new std::vector<int>(std::move(data))) { }
// we *are* sharing already -> no need to copy:
RowVector(std::shared_ptr<std::vector<int>& data) : _data(data) { }
Assignment operators analogously.
Side-note: If you want to have a mathmatical nxm matrix, pretty sure you don't want to have a jagged array. I'd assume your Matrix class' constructor already creates an appropriate vector of vectors, then for assignment, you'd have yet to check length:
// defaults not suitable any more!
RowVector& RowVector::operator=(RowVector const& other)
{
// still assuming shared pointer:
// (for vector, replace -> with .)
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = other._data;
}
RowVector(RowVector&& other)
{
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = std::move(other._data);
}

map with fixed (const) keys and changeable data? [duplicate]

I have a situation, where I would like to have a map that does not allow to add/remove keys after initialization, but the values are allowed to change (thus I cannot simply make the map const). Ie
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
I could write my own wrapper for std::map, but I have the feeling that it is something not too uncommon, so I wonder if there is already an existing solution.
Is there some standard idiom for a map that does not allow adding/removing keys, while the values may change?
ps: I know that the title alone is a bit vague, because the keys are already const in a map, but I hope it is clear what I mean...
Could you create a wrapper that contains the value that allows the value to be mutated when const and put that in the map instead? Something like:
template<typename T>
class Mutable {
mutable T value;
public:
const Mutable& operator=(const T& v) const { value = v; return *this; }
T& get() const { return value; }
};
Then your map can be of type
const std::map<int, Mutable<int>>
Live demo.
I usually regard this as a pitfall in C++ more than a feature, but, if it fits your application, you can just use pointer values.
#include <map>
#include <memory>
int main(int argc, char ** argv)
{
using namespace std;
const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} };
// *(myMap[1]) = 2; // Does not compile
*(myMap.at(1)) = 2;
for (auto & element : myMap)
{
*(element.second) = 0;
}
return 0;
}
Which is really just a simpler version of this other answer (obviously you may choose between shared_ptr / unique_ptr as needed).
Containers from the standard library are classes optimized for one usage that are expected to be used as is or included in higher level classes.
Here your requirement (keys fixed after initialization) is not covered by the standart library containers, so you will have to build your own implementation. As it will not be a std::map, you can just implement the operations you need, probably nothing more that operator []...
I understand that you simply want to disable the index access operator so that a user cannot accidentally add a default constructed item to the map. My solution is inspired by Chris Drew's solution but has the added benefit of remaining const correct (i.e. not allowing changing values of the map when the map is const).
Essentially, by disabling default construction you remove the ability to invoke the index access operator provided by std::map. The other methods will remain available since std::map is a class template and member functions won't be evaluated until they are invoked. Hence, std::map::at will work fine but std::map::operator[] will result in a compile-time error.
Inspired by Chris you can use a wrapper on the mapped_type to disable default construction. I took his demo and tweaked it a bit to demonstrate how to disable default construction and used it with std::map rather than a const std::map.
template<typename T>
class RemoveDefaultConstruction {
T value;
public:
RemoveDefaultConstruction() = delete; // The magic is here
RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default;
RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) :
value{std::forward<T>(t)} {
}
RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default;
RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default;
RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; }
RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; }
T const &get() const { return value; } // Keep const correctness
T &get() { return value; } // Keep const correctness
};
void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; }
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) {
//m.at(k) = v; // ERROR: Cannot change a const value
}
Live Demo
I see 2 options here
Make the map const and use const_cast when changing something
const std::map myMap;
myMap[1] = 2; // NOT OK, because const map
(const_cast&>(myMap)).at(1) = 2; // OK with const_cast
make an wrapper class or derive an custom map that has only read and update existing value methods
I don't think there is an built in way to make an map only with update value, and restrict and insert.

map with const keys but non const values?

I have a situation, where I would like to have a map that does not allow to add/remove keys after initialization, but the values are allowed to change (thus I cannot simply make the map const). Ie
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
I could write my own wrapper for std::map, but I have the feeling that it is something not too uncommon, so I wonder if there is already an existing solution.
Is there some standard idiom for a map that does not allow adding/removing keys, while the values may change?
ps: I know that the title alone is a bit vague, because the keys are already const in a map, but I hope it is clear what I mean...
Could you create a wrapper that contains the value that allows the value to be mutated when const and put that in the map instead? Something like:
template<typename T>
class Mutable {
mutable T value;
public:
const Mutable& operator=(const T& v) const { value = v; return *this; }
T& get() const { return value; }
};
Then your map can be of type
const std::map<int, Mutable<int>>
Live demo.
I usually regard this as a pitfall in C++ more than a feature, but, if it fits your application, you can just use pointer values.
#include <map>
#include <memory>
int main(int argc, char ** argv)
{
using namespace std;
const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} };
// *(myMap[1]) = 2; // Does not compile
*(myMap.at(1)) = 2;
for (auto & element : myMap)
{
*(element.second) = 0;
}
return 0;
}
Which is really just a simpler version of this other answer (obviously you may choose between shared_ptr / unique_ptr as needed).
Containers from the standard library are classes optimized for one usage that are expected to be used as is or included in higher level classes.
Here your requirement (keys fixed after initialization) is not covered by the standart library containers, so you will have to build your own implementation. As it will not be a std::map, you can just implement the operations you need, probably nothing more that operator []...
I understand that you simply want to disable the index access operator so that a user cannot accidentally add a default constructed item to the map. My solution is inspired by Chris Drew's solution but has the added benefit of remaining const correct (i.e. not allowing changing values of the map when the map is const).
Essentially, by disabling default construction you remove the ability to invoke the index access operator provided by std::map. The other methods will remain available since std::map is a class template and member functions won't be evaluated until they are invoked. Hence, std::map::at will work fine but std::map::operator[] will result in a compile-time error.
Inspired by Chris you can use a wrapper on the mapped_type to disable default construction. I took his demo and tweaked it a bit to demonstrate how to disable default construction and used it with std::map rather than a const std::map.
template<typename T>
class RemoveDefaultConstruction {
T value;
public:
RemoveDefaultConstruction() = delete; // The magic is here
RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default;
RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) :
value{std::forward<T>(t)} {
}
RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default;
RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default;
RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; }
RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; }
T const &get() const { return value; } // Keep const correctness
T &get() { return value; } // Keep const correctness
};
void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; }
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) {
//m.at(k) = v; // ERROR: Cannot change a const value
}
Live Demo
I see 2 options here
Make the map const and use const_cast when changing something
const std::map myMap;
myMap[1] = 2; // NOT OK, because const map
(const_cast&>(myMap)).at(1) = 2; // OK with const_cast
make an wrapper class or derive an custom map that has only read and update existing value methods
I don't think there is an built in way to make an map only with update value, and restrict and insert.

Container of fixed dynamic size

Is there a standard container for a sequence of fixed length, where that length is determined at runtime. Preferrably, I'd like to pass an argument to the constructor of each sequence element, and use that argument to initialize a const member (or a reference). I'd also like to obtain the sequence element at a given index in O(1). It seems to me that all of my requirements cannot be met at the same time.
I know std::array has fixed length, but that length has to be known at compile-time.
std::vector has dynamic size, and allows passing contructor arguments using emplace. Although you can reserve memory to avoid actual reallocations, the type still has to be movable to theoretically allow such reallocations, which e.g. prevents const members.
Then there is std::list and std::forward_list, which don't require a movable type, but which are still resizable and will perform rather poorly under random-access patterns. I also feel that there might be considerable overhead associated with such lists, since each list node will likely be allocated separately.
Strangely enough, std::valarray is my best bet so far, since it has a fixed length and won't resize automatically. Although there is a resize method, your type won't have to be movable unless you actually call that method. The main deficit here is the lack for custom constructor arguments, so initializing const members isn't possible with this approach.
Is there some alternative I missed? Is there some way to adjust one of the standard containers in such a way that it satisfies all of my requirements?
Edit: To give you a more precise idea of what I'm trying to do, see this example:
class A {
void foo(unsigned n);
};
class B {
private:
A* const a;
const unsigned i;
public:
B(A* aa) : a(aa), i(0) { }
B(A* aa, unsigned ii) : a(aa), i(ii) { }
B(const std::pair<A*, unsigned>& args) : B(args.first, args.second) { }
B(const B&) = delete;
B(B&&) = delete;
B& operator=(const B&) = delete;
B& operator=(B&&) = delete;
};
void A::foo(unsigned n) {
// Solution using forward_list should be guaranteed to work
std::forward_list<B> bs_list;
for (unsigned i = n; i != 0; --i)
bs_list.emplace_front(std::make_pair(this, i - 1));
// Solution by Arne Mertz with single ctor argumen
const std::vector<A*> ctor_args1(n, this);
const std::vector<B> bs_vector(ctor_args1.begin(), ctor_args1.end());
// Solution by Arne Mertz using intermediate creator objects
std::vector<std::pair<A*, unsigned>> ctor_args2;
ctor_args2.reserve(n);
for (unsigned i = 0; i != n; ++i)
ctor_args2.push_back(std::make_pair(this, i));
const std::vector<B> bs_vector2(ctor_args2.begin(), ctor_args2.end());
}
Theoretically vector has the properties you need. As you noted, actions that possibly do assignments to the contained type, including especially any sequence modifications (empace_back, push_back, insert etc.) are not supported if the elements are noncopyable and/or nonassignable. So to create a vector of noncopyable elements, you'd have to construct each element during vector construction.
As Steve Jessop points out in his answer, if you define the vector const in the first place you won't even be able to call such modifying actions - and of course the elements remain unchanged as well.
If I understand correctly, you have only a sequence of constructor arguments, not the real object sequence. If it's only one argument and the contained type has a corresponding constructor, things shoule be easy:
struct C
{
const int i_;
C(int i) : i_(i) {}
};
int main()
{
const std::vector<C> theVector { 1, 2, 3, 42 };
}
If the constructor is explicit, you have to make a list first or explicitly construct the objects in the initializer-list:
int main()
{
auto list = { 1, 2, 3, 4 };
const std::vector<C> theVector (std::begin(list), std::end(list));
const std::vector<C> anotherVector { C(1), C(44) };
}
If it's more than just one argument per constructed object, consider a intermediate creator object:
struct C
{
const int i_;
C(int i, int y) : i_(i+y) {}
};
struct CCreator
{
int i; int y;
explicit operator C() { return C(i,y); }
};
int main()
{
const std::vector<CCreator> ctorArgs = { {1,2}, {3,42} };
const std::vector<C> theVector { begin(ctorArgs), end(ctorArgs) };
}
I think const std::vector<T> has the properties you ask for. Its elements aren't actually defined with const, but it provides a const view of them. You can't change the size. You can't call any of the member functions that need T to be movable, so for normal use they won't be instantiated (they would be if you did an extern class declaration, so you can't do that).
If I'm wrong, and you do have trouble because T isn't movable, try a const std::deque<T> instead.
The difficulty is constructing the blighter -- in C++11 you can do this with an initializer list, or in C++03 you can construct a const vector from a non-const vector or from anything else you can get iterators for. This doesn't necessarily mean T needs to be copyable, but there does need to be a type from which it can be constructed (perhaps one you invent for the purpose) .
Add a level of indirection by using a std::shared_ptr. The shared pointer can be copied and assigned as usual, but without modifying the object that is pointed to. This way you should not have any problems, as the following example shows:
class a
{
public:
a(int b) : b(b) { }
// delete assignment operator
a& operator=(a const&) = delete;
private:
// const member
const int b;
};
// main
std::vector<std::shared_ptr<a>> container;
container.reserve(10);
container.push_back(std::make_shared<a>(0));
container.push_back(std::make_shared<a>(1));
container.push_back(std::make_shared<a>(2));
container.push_back(std::make_shared<a>(3));
Another advantage is the function std::make_shared which allows you to create your objects with an arbitrary number of arguments.
Edit:
As remarked by MvG, one can also use std::unique_ptr. Using boost::indirect_iterator the indirection can be removed by copying the elements into a new vector:
void A::foo(unsigned n)
{
std::vector<std::unique_ptr<B>> bs_vector;
bs_vector.reserve(n);
for (unsigned i = 0; i != n; ++i)
{
bs_vector.push_back(std::unique_ptr<B>(new B(this, i)));
}
typedef boost::indirect_iterator<std::vector<std::unique_ptr<B>>::iterator> it;
// needs copy ctor for B
const std::vector<B> bs_vector2(it(bs_vector.begin()), it(bs_vector.end()));
// work with bs_vector2
}
I also encounter this problem, the use case in my code is to provide a thread-safe vector, the elements number is fixed and are atomic numbers. I have read all the great answers here. I think we may also consider my solution:
Just inherited the std::vector and hide the modifiers such as push_back, emplace_back, erase, then we get a fixed size vector. We can only access and modify the elements with operator [].
template <typename T>
class FixedVector : protected std::vector<T> {
public:
using BaseType = std::vector<T>;
FixedVector(size_t n) : BaseType(n) {}
FixedVector(const T &val, size_t n) : BaseType(val, n) {}
typename BaseType::reference operator[](size_t n) {
return BaseType::operator[](n);
}
};