Could anybody tell me why the for_each() doesn't work in the code below.
I need it to check if the third element in the tuple if not a nullptr and if it is not then add the first and third elements to list
However, it seems to be adding all elements to list.
std::vector<std::tuple<std::string, std::type_index, Value>> arguments;
std::vector<std::pair<std::string, mv::Value>> class::defaultValues() const
{
std::vector<std::pair<std::string, Value>> list;
list.reserve((arguments.size()));
std::for_each(arguments.begin(), arguments.end(),[&list](std::tuple<std::string, std::type_index, Value> arg)
{
if (&std::get<2>(arg) != nullptr)
list.push_back(make_pair(std::get<0>(arg),std::get<2>(arg)));
}
);
return list;
}
Update:
Value is a class.
What the default constructor is called for it, It populates a ptr_ to be a nullptr.
Value() : ptr_(nullptr)
{
}
&std::get<2>(arg) returns the memory address of the Value object itself, not the value of the ptr_ that it holds 1. That address will NEVER be null.
1: unless Value overrides operator& to return ptr_, which should not be done!
You need to drop the & so you are comparing the actual Value object. But that will work in your example only if Value has implemented operator== to take a T* (where T is the type of ptr_) or a nullptr_t as input and compares it to ptr_. Otherwise, your lambda would have to access and compare ptr_ directly instead.
You should also be passing the lambda's arg parameter by reference instead of by value, so that you are acting on the original tuple stored in arguments, and not on a copy of it.
Try this:
std::for_each(arguments.begin(), arguments.end(),
[&list](std::tuple<std::string, std::type_index, Value> &arg)
{
if (std::get<2>(arg) != nullptr) // or std::get<2>(arg).ptr_, depending on how Value is implemented
list.push_back(std::make_pair(std::get<0>(arg), std::get<2>(arg)));
}
In this situation, I would suggest making Value implement operator! instead (if it does not already) to return whether its ptr_ is nullptr, then you can do this:
std::for_each(arguments.begin(), arguments.end(),
[&list](std::tuple<std::string, std::type_index, Value> &arg)
{
if (!!std::get<2>(arg))
list.push_back(std::make_pair(std::get<0>(arg), std::get<2>(arg)));
}
Or, implement operator bool to return whether ptr_ is not nullptr, or implement operator T* to return ptr_ instead (where T is the type of ptr_), then you can do this:
std::for_each(arguments.begin(), arguments.end(),
[&list](std::tuple<std::string, std::type_index, Value> &arg)
{
if (std::get<2>(arg))
list.push_back(std::make_pair(std::get<0>(arg), std::get<2>(arg)));
}
Because &std::get<2>(arg) can never be nullptr. You are literally getting a pointer (with &) to some Value & returned from std::get<2>(arg).
Related
I find the update operation on std::set tedious since there's no such an API on cppreference. So what I currently do is something like this:
//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);
Basically the iterator return by Set is a const_iterator and you can't change its value directly.
Is there a better way to do this? Or maybe I should override std::set by creating my own (which I don't know exactly how it works..)
set returns const_iterators (the standard says set<T>::iterator is const, and that set<T>::const_iterator and set<T>::iterator may in fact be the same type - see 23.2.4/6 in n3000.pdf) because it is an ordered container. If it returned a regular iterator, you'd be allowed to change the items value out from under the container, potentially altering the ordering.
Your solution is the idiomatic way to alter items in a set.
C++17 introduced extract, see Barry's answer.
If you're stuck with an older version, there are 2 ways to do this, in the easy case:
You can use mutable on the variable that are not part of the key
You can split your class in a Key Value pair (and use a std::map)
Now, the question is for the tricky case: what happens when the update actually modifies the key part of the object ? Your approach works, though I admit it's tedious.
In C++17 you can do better with extract(), thanks to P0083:
// remove element from the set, but without needing
// to copy it or deallocate it
auto node = Set.extract(iterator);
// make changes to the value in place
node.value() = 42;
// reinsert it into the set, but again without needing
// to copy or allocate
Set.insert(std::move(node));
This will avoid an extra copy of your type and an extra allocation/deallocation, and will also work with move-only types.
You can also extract by key. If the key is absent, this will return an empty node:
auto node = Set.extract(key);
if (node) // alternatively, !node.empty()
{
node.value() = 42;
Set.insert(std::move(node));
}
Update: Although the following is true as of now, the behavior is considered a defect and will be changed in the upcoming version of the standard. How very sad.
There are several points that make your question rather confusing.
Functions can return values, classes can't. std::set is a class, and therefore cannot return anything.
If you can call s.erase(iter), then iter is not a const_iterator. erase requires a non-const iterator.
All member functions of std::set that return an iterator return a non-const iterator as long as the set is non-const as well.
You are allowed to change the value of an element of a set as long as the update doesn't change the order of elements. The following code compiles and works just fine.
#include <set>
int main()
{
std::set<int> s;
s.insert(10);
s.insert(20);
std::set<int>::iterator iter = s.find(20);
// OK
*iter = 30;
// error, the following changes the order of elements
// *iter = 0;
}
If your update changes the order of elements, then you have to erase and reinsert.
You may want to use an std::map instead. Use the portion of Element that affects the ordering the key, and put all of Element as the value. There will be some minor data duplication, but you will have easier (and possibly faster) updates.
I encountered the very same issue in C++11, where indeed ::std::set<T>::iterator is constant and thus does not allow to change its contents, even if we know the transformation will not affect the < invariant. You can get around this by wrapping ::std::set into a mutable_set type or write a wrapper for the content:
template <typename T>
struct MutableWrapper {
mutable T data;
MutableWrapper(T const& data) : data(data) {}
MutableWrapper(T&& data) : data(data) {}
MutableWrapper const& operator=(T const& data) { this->data = data; }
operator T&() const { return data; }
T* operator->() const { return &data; }
friend bool operator<(MutableWrapper const& a, MutableWrapper const& b) {
return a.data < b.data;
}
friend bool operator==(MutableWrapper const& a, MutableWrapper const& b) {
return a.data == b.data;
}
friend bool operator!=(MutableWrapper const& a, MutableWrapper const& b) {
return a.data != b.data;
}
};
I find this much simpler and it works in 90% the cases without the user even noticing there to be something between the set and the actual type.
This is faster in some cases:
std::pair<std::set<int>::iterator, bool> result = Set.insert(value);
if (!result.second) {
Set.erase(result.first);
Set.insert(value);
}
If the value is usually not already in the std::set then this can have better performance.
I have a key and I want to change the value of the key with another json object.
json newjs = ...;
json tempjs = ...;
newjs["key"] = tempjs["key"];
What will happen to the data existed in newjs["key"] previously?
Will nlohmann class automatically destroy it or is it a memory leak?
OR do I need to manually erase the key first and assign as above?
Internally it's a kept by an "ordered_map: a minimal map-like container that preserves insertion order".
The actual standard container used in this ordered_map is a std::vector<std::pair<const Key, T>, Allocator> and the assignment you do is performed via
T& operator[](const Key& key)
{
return emplace(key, T{}).first->second;
}
where emplace is defined as:
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
{
return {it, false};
}
}
Container::emplace_back(key, t);
return {--this->end(), true};
}
This means that operator[] tries to emplace a default initialized T into the internal map. If key isn't present in the map, it will succeed, otherwise it will fail.
Regardless of which, when emplace returns, there will be a T in the map and it's a reference to that T that is returned by operator[] and it's that you then copy assign to.
It's a "normal" copy assignment and no leaks should happen.
I'm getting the following error when trying to return the value using the operator*() in my custom iterator.
error: invalid initialization of non-const reference of type 'char&' from a temporary of type 'char'
If anyone is able to help me out, that would be great!
The specifics of the code is as follows:
Test code:
for(btree<char>::iterator itr = tree.begin(); itr != tree.end(); ++itr) {
cout << *itr << " "; // <- this line complains about the * operator.
}
The operator*() code:
template <typename T> typename btree_iterator<T>::reference btree_iterator<T>::operator*() const {
return pointee_->value(); // <- this line is where the error above is produced from.
}
pointee_ from the btree_iterator class is a private variable defined as follows:
btree_node<T>* pointee_;
reference is typefef'ed as the following in the btree_iterator class:
typedef T& reference;
value() is defined in the btree_node class as follows:
T value() const;
// function definition.
template <typename T> T btree_node<T>::value() const { return value_; }
value is initially stored into a btree_node via it's constructor as follows:
template <typename T> btree_node<T>::btree_node(const T& elem) : value_(elem), nextCont_(NULL), prevCont_(NULL), nextNode_(NULL), prevNode_(NULL) {}
Please let me know if i missed including any crucial information, and apologies if i did!
Based on the error, it sounds like I'm trying to return a reference to a local variable. The iterator itself may be local, but the value that it is returning shouldn't be, since the node constructor originally takes in a reference, and stores that into the node.
Thanks in advance, and regards!
You're trying to use a reference to a temporary variable
template <typename T> T btree_node<T>::value() const { return value_; }
^^^
This returns a temporary copy of value_.
template <typename T> typename btree_iterator<T>::reference btree_iterator<T>::operator*() const {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return pointee_->value(); // <- this line is where the error above is produced from.
}
This returns a reference to that temporary copy. You most likely want value() to return a reference, but this is up to you - a reference allows clients of your btree to alter the contents. Especially if the tree is ordered based upon the value of the node, you may not want to allow this. Have a think how this is relevant to your design.
pointee_->value() returns a values which is basically a fresh copy. Hence this value is local in operator* and you can't return a reference to that.
I'd recommend doing it just like most containers do, i.e. having both, iterator and const_iterator, whereas const_iterator returns a const reference and iterator returns a reference. The same principle applies to value(). Have versions returning a ref and a const ref.
If you ever want to work on copies, you can create them from the reference in client code. If you don't want to allow chanign the values, simply drop (or make private, or whatever) the non-const parts. It think it also fits what people using your btree expect:
Iterators do not make copies somewhere but you iterator over the data inside teh data structure. If you want copies, you can make them.
I'm writing a simple hash map class:
template <class K, class V> class HashMap;
The implementation is very orthodox: I have a heap array which doubles in size when it grows large. The array holds small vectors of key/value pairs.
Vector<Pair<K, V> > *buckets;
I would like to overload the subscript operator in such a way that code like this will work:
HashMap<int, int> m;
m[0] = 10; m[0] = 20;
m[2] = m[1] = m[0];
In particular,
For m[k] = v where m does not contain k, I'd like a new entry to be added.
For m[k] = v where m does contain k, I'd like the old value to be replaced.
In both of these cases, I'd like the assignment to return v.
Presumably the code will look something like
V& operator[](K &key)
{
if (contains(key))
{
// the easy case
// return a reference to the associated value
}
else
{
Vector<Pair<K, V> > *buck = buckets + hash(k) % num_buckets;
// unfinished
}
}
How should I handle the case where the key is not found? I would prefer to avoid copying values to the heap if I can.
I suppose I could make a helper class which overloads both the assignment operator and a cast to V, but surely there is a simpler solution?
Edit: I didn't realize that std::map required that the value type have a zero argument constructor. I guess I will just default-construct a value as well.
How should I handle the case where the key is not found?
Insert a new element with that key and return a reference to the value of that new element. Effectively, your pseudocode becomes something equivalent to:
if (!contains(key))
insert(Pair<K, V>(key, V()));
return reference_to_the_element_with_that_key;
This is exactly what your requirement is, too. You said "For m[k] = v where m does not contain k, I'd like a new entry to be added."
How should I handle the case where the key is not found?
std::map creates a new object, and inserts it into the map, and returns its reference. You can also do the same.
Alternatively, you can throw an exception KeyNotFoundException like the way .NET map throws. Of course, you've to define KeyNotFoundException yourself, possibly deriving from std::runtime_exception.
By the way, as a general rule, always implement operator[] in pair as:
V &operator[](const K &key);
const V &operator[](const K &key) const;
Just for the sake for const-correctness. However, if you decide to create a new object and insert it into the map, when the key is not found, then this rule is not applicable here, as const version wouldn't make sense in this situation.
See this FAQ:
What's the deal with "const-overloading"?
It sounds like what you want is a "smart reference", which you cannot generically implement in C++ because you cannot overload the dot operator (among other reasons).
In other words, instead of returning a reference to a V, you would return a "smart reference" to a V, which would contain a pointer to V. That smart reference would implement operator=(const V &v) as this->p = new V(v), which only requires a copy constructor (not a zero-argument constructor).
The problem is that the smart reference would have to behave like an actual reference in all other ways. I do not believe you can implement this in C++.
One not-quite-solution is to have your constructor take a "default" instance of V to use for initializing new entries. And it could default to V().
Like this:
template<class K, class V> class HashMap {
private:
V default_val;
public:
HashMap(const V& def = V()) : default_val(def) {
...
}
...
};
When V lacks a zero-argument constructor, HashMap h will not compile; the user will need to provide a V object whose value will be returned when a key is accessed for the first time.
This assumes V has a copy constructor, of course. But from your examples, that seems like a requirement anyway.
The simple solution is to do as std::map does: construct a new entry,
using the default constructor of the value type. This has two
drawbacks: you won't be able to use [] on a HashMap const, and you
can't instantiate HashMap with a value type which doesn't have a default
constructor. The first is more or less implicit in the specification,
which says that [] may modify the map. There are several solutions
for the second: the simplest is probably to pass an instance of a
"default" value to the constructor, which saves it, and uses it to copy
construct the new instance, e.g.:
template <typename Key, typename Value>
class HashMap
{
// ...
Value m_defaultValue;
public:
HashMap( ..., Value const& defaultValue = Value() )
: ... , m_defaultValue( defaultValue )...
Value& operator[]( Key& key )
{
// ...
// not found
insert( key, m_defaultValue );
// return reference to newly inserted value.
}
};
Alternatively, you can have operator[] return a proxy, something like:
template <typename Key, typename Value>
class HashMap::Helper // Member class of HashMap
{
HashMap* m_owner;
Key m_key;
public:
operator Value&() const
{
if ( ! m_owner->contains( m_key ) )
m_owner->createEntryWithDefaultValue( m_key );
return m_owner->getValue( m_key );
}
Helper& operator=( Value const& newValue ) const
{
m_owner->insert( m_key, newValue );
return *this;
}
};
Note that you'll still need the default value for the case where someone
writes:
v = m[x];
and x isn't present in the map. And that things like:
m[x].f();
won't work. You can only copy the entire value out or assign to it.
(Given this, I'd rather prefer the first solution in this case. There
are other cases, however, where the proxy is the only solution, and we
have to live with it.)
I've been reading about the "this" pointer on various sites (e.g. the MSDN manuals) and understand its basic uses -- returning a copy your own object or using a pointer of it for returns/comparison.
But I came across this statement:
// Return an object that defines its own operator[] that will access the data.
// The temp object is very trivial and just allows access to the data via
// operator[]
VectorDeque2D_Inner_Set<T> operator[](unsigned int first_index) {
return VectorDeque2D_Inner_Set<T>(*this, first_index);
}
What does that do? Does it somehow increment the this operator, and if so, why??
(This comes from an example I was given on stack overflow, so there may be mistakes in the syntax. Let me know if a bigger chunk is necessary, I can paste more code in.)
EDIT 1
Here's the entire listing, for more info. The function is near the bottom of the class. Note I renamed the variable from x to index and renamed the templated inner class. I forgot to put the typecast to the templated inner-class, which I have added in this update.
Any ideas now?
template <typename T>
class Container
{
private:
// ...
public:
// Proxy object used to provide the second brackets
template <typename T>
class OperatorBracketHelper
{
Container<T> & parent;
size_t firstIndex;
public:
OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}
// This is the method called for the "second brackets"
T & operator[](size_t SecondIndex)
{
// Call the parent GetElement method which will actually retrieve the element
return parent.GetElement(firstIndex, SecondIndex);
}
}
// This is the method called for the "first brackets"
OperatorBracketHelper<T> operator[](size_t FirstIndex)
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper<T>(*this, FirstIndex);
}
T & GetElement(size_t FirstIndex, size_t SecondIndex)
{
// Here the actual element retrieval is done
// ...
}
}
The * operator dereferences the this pointer. This is necessary because the method being called ( constructor OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) ) requires a reference rather than a pointer.
Is this a fail pattern? I dunno. It smells to me on an instinctive level, but I can't find anything directly wrong with it.
The this keyword basically is a pointer reference to the object that it's currently in use. In C++, this is a pointer, so to dereference it, use *this.
So, this code,
return VectorDeque2D_Inner_Set<T>(*this, index);
returns a new VectorDeque2D_Inner_Set by passing a dereferenced of itself (since the constructor wants the reference of the object and not the pointer address).
This method,
// This is the method called for the "first brackets"
OperatorBracketHelper<T> operator[](size_t FirstIndex)
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper<T>(*this, FirstIndex);
}
just passed a dereferenced self to the constructor OperatorBracketHelper as it requires a Container& as parameter.
it creates an instance of OpBracketHelper with the a reference to the current Container as its parent member (*this passes in a reference to the container object to the constructor)
My only concern would be about lifetimes of the Container and the helper object. I would be tempted to use shared_ptr rather than a reference