std::map default value
No, there isn't. The simplest solution is to write your own free template function to do this. Something like:
#include <string>
#include <map>
using namespace std;
template <typename K, typename V>
V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval ) {
typename std::map<K,V>::const_iterator it = m.find( key );
if ( it == m.end() ) {
return defval;
}
else {
return it->second;
}
}
int main() {
map <string,int> x;
...
int i = GetWithDef( x, string("foo"), 42 );
}
C++11 Update
Purpose: Account for generic associative containers, as well as optional comparator and allocator parameters.
template <template<class,class,class...> class C, typename K, typename V, typename... Args>
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval)
{
typename C<K,V,Args...>::const_iterator it = m.find( key );
if (it == m.end())
return defval;
return it->second;
}
map int,int default values
As soon as you access the map with the [] operator, if the key doesn't exist it gets added. The int gets "value initialization" invoked - so it will get a value of 0.
Function to provide a default value when working with std::map
First of all you use operator[]
on the map object inside the function. That will never be allowed because it is a non-const function and you have passed the map by const reference. Instead you should rewrite the function implementation to use iterators:
template<typename KeyType, typename ValueType>
ValueType mapDefaultInf(const std::map<KeyType, ValueType> & map, const KeyType & key)
{
const auto it = map.find(key);
return it != map.end() ? it->second : std::numeric_limits<ValueType>::infinity();
}
Second of all you have an ambiguity in the key type. You need to pass in a std::string. Like this:
auto el = mapDefaultInf(map, std::string("alexey"));
std::map default value (move only types)
This can be achieved with a proxy object.
template <typename T>
class PossiblyOwner
{
public:
struct Reference {};
PossiblyOwner(const PossiblyOwner & other)
: m_own(other.m_own),
m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
{}
PossiblyOwner(PossiblyOwner && other)
: m_own(std::move(other.m_own)),
m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
{}
PossiblyOwner(T && val) : m_own(std::move(val)), m_ref(m_own.value()) {}
PossiblyOwner(const T & val) : m_own(val), m_ref(m_own.value()) {}
PossiblyOwner(Reference, const T & val) : m_ref(val) {}
const T& value () const { return m_ref; }
operator const T& () const { return m_ref; }
// convenience operators, possibly also define ->, +, etc.
// but they are not strictly needed
auto operator *() const { return *m_ref; }
private:
std::optional<T> m_own;
const T & m_ref;
};
// Not strictly required
template <typename T>
std::ostream & operator<<(std::ostream & out,
const PossiblyOwner<T> & value)
{
return out << value.value();
}
template <typename Container, typename Key, typename ...DefaultArgs>
auto GetOrDefault(const Container & container, const Key & key,
DefaultArgs ...defaultArgs)
-> PossiblyOwner<decltype(container.find(key)->second)>
{
auto it = container.find(key);
using value_type = decltype(it->second);
using ret_type = PossiblyOwner<value_type>;
if (it == container.end())
return {value_type(std::forward<DefaultArgs>(defaultArgs)...)};
else
return {typename ret_type::Reference{}, it->second};
}
Then the usage can be:
int main()
{
std::map<int, std::unique_ptr<std::string>> mapping;
mapping.emplace(1, std::make_unique<std::string>("one"));
mapping.emplace(2, std::make_unique<std::string>("two"));
mapping.emplace(3, std::make_unique<std::string>("three"));
std::cout << *GetOrDefault(mapping, 0,
std::make_unique<std::string>("zero")) << "\n";
std::cout << *GetOrDefault(mapping, 1,
std::make_unique<std::string>("one1")) << "\n";
std::cout << *GetOrDefault(mapping, 3,
new std::string("three1")) << "\n";
}
Edit
I have noticed that the default copy constructor of PossiblyOwner<T>
causes undefined behavior, so I had to define a non-default copy and move constructors.
Default value of static std::unordered_map
Yes, it is actually safe to assume that the values inside Foo
are always initialized to zero because of the behaviour of operator[]
When the default allocator is used, this results in the key being copy/move constructed from key and the mapped value being value-initialized.
You do not provide a constructor which means that each field in Foo
will be value initialized individually which for primitive types means zero initialization.
but
The problem you are actually facing here is that a field called "Apple"
does not exist in your map. Unfortunately the semantics of operator[]
are such that if the value does not exist, it will be created on the fly. You probably didn't even want to access a non-existent field in the map and you are asking whether it is always initialized to zero so that you can use this fact to check whether the element was there. For this purpose however, you should either use the find()
or at()
member function.
find()
will return an iterator pointing to the end of the map if the element does not exist. That means you could guards the element access usingif (auto apple = map.find("Apple"); apple != map.end()) {
std::cout << apple->second.num << '\n';
std::cout << apple->second.state << '\n';
}(with the C++17
if
statement initializer)at()
will throw an exception if the element is not found.std::cout << map.at("Apple").num << '\n';
std::cout << map.at("Apple").state << '\n';This will crash your program with a
std::out_of_range
exception. You might feel temped to catch this exception to check whether the element existed. Don't do this. It is very bad practice to use exceptions for control flow. On top of that exception are dead slow when they are being thrown.
std::map default value for build-in type
This is defined in the standard, yes. map is performing "default initialization" in this case. As you say, for class types, that calls a no-arguments constructor.
For built-in types, in the '98 standard, see section 8.5, "Initializers":
To default-initialize an object of type T means:
- if T is a non-POD ...
- if T is an array type ...
- otherwise, the storage for the object is zero-initialized
And, previously,
To zero-initialize storage for an object of type T means:
- if T is a scalar type, the storage is set to the value 0 (zero) converted to T
Scalar types are:
- Arithmetic types (integer, floating point)
- Enumeration types
- Pointer types
- Pointer to member types
In particular, the behaviour you see with an integer (initialized to zero) is defined by the standard, and you can rely on it.
Default value of a pointer in a new std::map entry
If the key is not found in the map, the inserted value is value-initialized (§23.4.4.3/1). So no need for a wrapper; the pointer inserted will be a null pointer.
set default value of unordered map if key doesn't exist
One possibility would be to create a tiny class for the value type:
class dproxy {
double value_;
public:
dproxy(double value = std::numeric_limits<double>::max())
: value_{value} {}
operator double &() { return value_; }
operator double const &() const { return value_; }
};
std::unordered_map<Pair, dproxy> lFunction;
A default-constructed dproxy
will be initialized to std::numeric_limits<double>::max()
, and a dproxy will implicitly convert to a (reference to a) double
. This can impose limitations if you're doing a lot of implicit conversions otherwise though (e.g., if you had some other function foo
that took some other type bar
that could be implicitly constructed from a double
, foo(lFunction[baz]);
would work if lFunction
contained double
s, but not if it contained dproxy
objects, since an implicit conversion sequence can only use one user-defined conversion).
Default value for the second element of the map STL?
what is the default value for the second element in map STL if I am initializing it with an array?
When accessing a key-value pair (kvp) in a std::map
with operator[]
, either the key already exists, or a new kvp is constructed and the mapped_type
is value-initialised. A value-initialized int
is always 0. This imposes a requirement that it must be default constructible. Note that you can also access entries in a map using the at
member function, which throws if the key is not found.
How can this program return the frequency of the element in the array by accessing the second element of map mp?
You have done this correctly in your code snippet. You could have used a std::multiset
or std::unordered_multiset
, they provide a count member function, that is the frequency of the key.
#include <set>
#include <iostream>
int main()
{
int arr[] = { 10, 20, 20, 10, 10, 20, 5, 20 };
std::multiset<int> freq (std::begin(arr), std::end(arr));
for(auto elem = freq.begin();
elem != freq.end();
elem=freq.upper_bound(*elem)) // Traverse the unique elements
{
std::cout << *elem << " count: " << freq.count(*elem) << "\n";
}
}
Godbolt
Note that your question mentions std::map
but the example you provided references std::unordered_map
, much of this applies to both data-structures.
std::map default value for enums
Will the initialization always be zero-initialization for enumerations? namely
abc[0]
is always initialized as the enumerator corresponding to0
?
Yes.
What if we have
enum X {
X1 = 1,
...
What will
abc[0]
be?
It will be 0
.
Working program (also can be seen at http://ideone.com/RVOfT6):
#include <iostream>
#include <map>
enum X {
X1,
X2,
X3
};
int main()
{
X x = {};
std::map<int, X> abc;
std::cout << x << std::endl;
std::cout << abc[0] << std::endl;
}
Output:
0
0
Related Topics
Should I Pass an Std::Function by Const-Reference
How to Safely Use Openmp with C++11
What Are the Differences Between Overriding Virtual Functions and Hiding Non-Virtual Functions
Inheritance or Composition: Rely on "Is-A" and "Has-A"
How to Set the Baud Rate to 307,200 on Linux
Efficient Bitwise Operations for Counting Bits or Find the Right|Left Most Ones
How to Create a Window in Different Qt Threads
C++: Can Vector<Base> Contain Objects of Type Derived
Differencebetween Set and Unordered_Set in C++
Remove an Array Element and Shift the Remaining Ones
How to Identify the File Content as Ascii or Binary
(Partially) Specializing a Non-Type Template Parameter of Dependent Type
Gcc Equivalent of Ms's /Bigobj