Does boost::optional trigger a ref count on shared_ptr? - c++

I'm trying to get a function to return an optional value from my map. So something like this:
boost::optional<V> findValue(const K& key) {
boost::optional<V> ret;
auto it = map.find(key);
if (it != map.end()) {
ret = it->second;
}
return ret;
}
If V happens to be a shared_ptr type of some kind, does the assignment to ret trigger a reference count?

Yes, it has to. boost::optional stores a copy, so for a shared_ptr, this means there is a copy of the shared_ptr and that means the reference count must be increased.
Note that as long as the boost::optional is empty, i.e., it doesn't contain a value of shared_ptr, there is no object whose reference count is fiddled with. In other words, an empty boost::optional does not contain an (empty or otherwise) shared_ptr.
The requested "semantics" can't really work because you keep one shared_ptr in the map and you return a shared_ptr.
However, you may return a boost::optional<const V&>:
boost::optional<const V&> findValue(const K& key) {
auto it = map.find(key);
if (it != map.end()) {
return boost::optional<const V&>( it->second );
}
return boost::optional<const V&>();
}
but make sure that the reference remains valid while you keep/use it.

Yes. Copying a shared pointer, in this case by copy-initialising the one contained in the optional object, will increment the use count.

Related

`auto` for the result of `std::set::find` in non-const context resolves to `std::_Rb_tree_const_iterator` in g++ (GCC) 7.3.0 with `-std=c++11` [duplicate]

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.

Who deletes previous nlohmann json object resources when value is replaced?

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.

c++ for_each() lamda function not correct

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).

How to create a temporary variable in C++

I have a function returning a reference to an instance of my class "record".
record& get_record(int key) {
return lookup(key);
}
That is effective it returns a reference and not by value. Now I modify it a bit.
record& get_record(int key) {
if (valid(key))
return lookup(key);
else {
record x;
x.valid=false;
return x; //Here I really want to return a temporary variable
// and not a reference to a local variable.
}
}
Is it correct that returning a reference to a local variable is not a good idea? and how do I return x in such a way that it becomes a temporary variable?
This is worse than a bad idea, it is undefined behavior and result in most of the cases to a crash. This is bad (TM).
What you could do is changing the return type of get_record so it returns a smart pointer. If key is valid, it returns an observer pointer to it. Otherwise, it returns an owning smart pointer to a freshly created object:
#include <memory>
#include <iostream>
struct record { int n; } some_record{42};
std::shared_ptr<record> get_record(bool b)
{
if (b == true) {
return std::shared_ptr<record>{&some_record, [](record*){}}; // see explanation ^1
}
return std::shared_ptr<record>{new record{0}};
}
int main()
{
std::cout << get_record(true)->n << "\n"; // this is some_record
std::cout << get_record(false)->n << "\n"; // this is a temporary
}
1) About [](record*){}: this no-op lambda given as the second argument to std::shared_ptr::shared_ptr() is invoked when the smart pointer is destroyed. It replaces the default deleter of std::shared_ptr whose behavior is to call delete on the owned pointer.
About why your design is flawed. In fact, making get_record return a reference makes it not consistent. What you want is:
if key is valid return a reference to an existing/permanant object, and
return a temporary object otherwise.
Those two are mutually exclusive, and your function doesn't make sense: what does get_record return semantically?
Is it correct that returning a reference to a local variable is not a good idea?
Yes. The local object will be destroyed when get out of the function so the returned reference is always dangled.
You might make x a static variable.
record& get_record(int key) {
if (valid(key))
return lookup(key);
else {
static record x;
x.valid=false;
return x;
}
}
Note that the returned reference will always refer to the same object, i.e. x.
If you are allowed to modify the get_record function you can change the return type to pointer to record instead of reference to record.
record* get_record( int key )
{
if( valid( key ) ) return &lookup( key );
else return nullptr;
}
However, this approach needs two guarantees:
the lookup function must return a reference to record
the record returned by lookup must still live when lookup returns (e.g. record is an element of some sort of container and lookup returns its reference)
As others already detail why returning a reference to a local is bad, ill just provide an alternative: Exceptions. Though you could write a custom exception, arguably an std::out_of_range exception would seem in place (as the key lies outside of the range of valid keys, which is exactly what std::map::at does).
Have a look at: How to throw a C++ exception
record& get_record(int key)
{
if (valid(key))
{
return lookup(key);
} else {
throw std::out_of_range("The provided key is invalid");
}
}
You will now, obviously, have to catch the exception in the code calling get_record, otherwise your program will still terminate.
Returning a reference in itself doesn't produce undefined behaviour, but if you attempt to modify it, then you will.
Accessing an object outside of its lifetime is undefined behavior.
int* foo(void) {
int a = 17; // a has automatic storage duration
return &a;
} // lifetime of a ends
int main(void) {
int* p = foo(); // p points to an object past lifetime ("dangling pointer")
int n = *p; // undefined behavior
}
http://en.cppreference.com/w/c/language/lifetime
If you have access to C++17, you could implement it using std::optional. Note the use of std::reference_wrapper, because use of a reference in std::optional makes your program ill-formed.
std::optional<std::reference_wrapper<record>> get_record(int key) {
if (valid(key))
return std::optional<std::reference_wrapper<record>>(lookup(key));
else
return std::nullopt;
}
Without C++17, you could just return a pointer to your record:
record* get_record(int key) {
if (valid(key))
return &lookup(key);
else
return nullptr;
}
Or if you prefer, you can keep the reference return type, and throw an exception to indicate a missing record. Though this is my least preferred approach as it makes it easy to call get_record without wrapping in a try / catch.
record& get_record(int key) {
if (valid(key))
return &lookup(key);
else
throw std::out_of_range("Invalid record key!");
}

Can I get away with putting auto_ptr in a STL container?

I am inheriting an interface, and implementing a virtual function that is supposed to do some work on a list of dynamically allocated objects. The first step is to remove duplicates from the list based on some custom equivalence criteria:
class Foo { /* ... */ };
struct FooLess
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
struct FooEqual
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
void doStuff(std::list<Foo*> &foos)
{
// use the sort + unique idiom to find and erase duplicates
FooLess less;
FooEqual equal;
foos.sort( foos.begin(), foos.end(), less );
foos.erase(
std::unique( foos.begin(), foos.end(), equal ),
foos.end() ); // memory leak!
}
The problem is that using sort + unique doesn't clean up the memory, and the elements to be erased have unspecified values after unique, so I cannot perform the cleanup myself before eraseing. I was considering something like this:
void doStuff(std::list<Foo*> &foos)
{
// make a temporary copy of the input as a list of auto_ptr's
std::list<auto_ptr<Foo>> auto_foos;
for (std::list<Foo>::iterator it = foos.begin(); it != foos.end(); ++it)
auto_foos.push_back(auto_ptr<Foo>(*it));
foos.clear();
FooLess less; // would need to change implementation to work on auto_ptr<Foo>
FooEqual equal; // likewise
auto_foos.sort( auto_foos.begin(), auto_foos.end(), less );
auto_foos.erase(
std::unique( auto_foos.begin(), auto_foos.end(), equal ),
auto_foos.end() ); // okay now, duplicates deallocated
// transfer ownership of the remaining objects back
for (std::list<auto_ptr<Foo>>::iterator it = auto_foos.begin();
it != auto_foos.end(); ++it)
{ foos.push_back(it->get()); it->release(); }
}
Will this be okay, or am I missing something?
I am not able to use C++11 (Boost might be possible) or change the function signature to accept a list of straightforward Foos.
To put an object into a standard container the object needs value semantics (the standard says "copy assignable" and "copy constructable"). Among other things, that means the copy constructor and assignment operator needs to create a copy of an object (leaving the original intact)
The auto_ptr copy constructor does not do that. Instead, the copy constructor and assignment operator transfer ownership of the pointer.
As a consequence, it is not possible for a standard container to contain an auto_ptr.
A lot of implementations (as in compiler and standard library) have the standard containers and/or auto_ptr coded so attempting to have a container of auto_ptr's will trigger a compiler error. Unfortunately, not all implementations do that.
There are generally the following methods you can use in C++98:
Define some pointer that will do what std::auto_ptr can't do. There was an old version of that thing, which contained an additional field of type bool that marked ownership. It was marked mutable, so it could be modified also in the object being read from when copying. The object was deleted at the end only if owned was true. Something like:
==
template <class T> class owning_ptr
{
T* ptr;
mutable bool owns;
public:
void operator =(T* src) { ptr = src; owns = true; }
owning_ptr(const owning_ptr& other)
{
// copy the pointer, but STEAL ownership!
ptr = other.ptr; owns = other.owns; other.owns = false;
}
T* release() { owns = false; return ptr; }
~owning_ptr() { if ( owns ) delete ptr; }
/* ... some lacking stuff ..*/
};
You may try out boost::shared_ptr
Instead of std::unique, you may try to do std::adjacent_find in a loop. Then you'll just find all elements that are "the same" as by your equal. If there's more than one element, you will erase them in place (you are allowed to do it because it's a list, so iterators remain valid).