Using try_emplace with a shared_ptr - c++

So I have a std::unordered_map<std::string, std::shared_ptr<T>> and I'd like to use try_emplace to add/reference elements. Previously, it was simply a std::unordered_map<std::string, T> and T has a constructor which just takes a std::string, so I was using myMap.try_emplace(myString, myString).first->second to reference the T and create it if necessary.
However, if I simply change it to myMap.try_emplace(myString, std::make_shared<T>(myString)).first->second, it, of course, constructs the T every time.
What's the most idiomatic way to get around this? To clarify, I'd like to construct the object on the heap with a shared pointer and insert the shared pointer into the unordered map if and only if there is not already a matching element in the map.

You can use operator[] instead:
auto &ptr = map[ key ];
if( !ptr ) ptr = std::make_shared<T>( myString );
Note: this solution came with assumption that you do not want to keep default constructed std::shared_ptr in the map. If that is the case, then you would need to use little more verbose code with try_emplace:
auto p = map.try_emplace( key, nullptr );
if( p.second ) p.first->second = std::make_shared<T>( myString );
else {
if( !p.first->second ) { // handle nullptr }
}
auto &ptr = p.first->second;

Write a factory function wrapper:
template<class F>
struct auto_factory_t {
F f;
operator decltype(std::declval<F&&>()()) && {
return std::move(f)();
}
};
template<class F>
auto_factory_t<std::decay_t<F>> wrap_factory(F&&f){
return {std::forward<F>(f)};
}
then
myMap.try_emplace(myString, wrap_factory([&]{return std::make_shared<T>(myString);})).first->second;
and done.
wrap_factory(f) returns an object containing f. It can be implicitly cast into the type f() returns, and when done so calls f().

Another option is to wrap the shared pointer in your own type. Then you can provide a constructor that takes a T and makes a shared_ptr<T>. This lets you use try_emplace and pass to it a T without having to have anything actually created if the object already exists. There is a lot of boiler plate involved in this though if you want to use the object as if it were a shared_ptr<T>.

What you may do:
// C++17, else you have to move declaration outside of the `if`
// and retrieve it/inserted from pair result.
if (auto [it, inserted] = myMap.try_emplace(myString, nullptr); inserted) {
it->second = std::make_shared<T>(myString);
}

Modern C++17 approach
template <class factory>
class deferred_factory {
public:
deferred_factory(factory&& mfactory) : mFactory{std::move(mfactory)} {}
// Wrap invocation of #c mFactory in an appropriate conversion operator.
/* implicit */ operator std::invoke_result_t<factory>() {
return mFactory();
}
private:
factory mFactory;
};
// Deduction guide for lvalue reference factories.
template <class factory>
deferred_factory(const factory&) -> deferred_factory<const factory&>;
Explanations
The basic trick is delaying initialization, i.e. invoking the factory. This is done by initializing the value type from another type (deferred_factory) which is implicitly convertible to the desired value type.
The conversion operator returns exactly the same type as invoking the factory directly. Due to mandatory copy/move elision with C++17, this imposes no extra copies whatsoever (no further && / std::move required).
With class template argument deduction, no further helpers for creating deferred_factorys are necessary. The final deduction guide allows reusing existing factories for multiple deferred_factorys which only wrap a reference to the original factory.
Usage
In OP's context
myMap.try_emplace("key", deferred_factory{[]{return std::make_shared<T>("value");}});
inserts "key" into myMap if and only if it hasn't been present before. The shared_ptr<T> is only ever created upon insertion.
This answer is a modern variant of Yakk - Adam Nevraumont's. All credit to him.

Related

Is std::optional<std::shared_ptr<MyClass>> good for avoiding null point deference?

I want to write safe C++ programs, therefore:
I wanted to avoid memory leaks, so I started using std::shared_ptr.
However, I still had some null pointer deferences some times. I've come up with the idea of using using MyClassSafe = std::optional<std::shared_ptr<MyClass>>.
Then I avoid both memory leaks and null pointer deference. Well, kind of. For example:
MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
//use it here
} else {
//do something in case no value
}
//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
//use it here, for example:
//this deferences a nullptr
myClassSafe.value()->someFunction();
} else {
//do something in case no value
}
so this is not much safer. It's better but I still can make mistakes.
I can imagine a safe_shared_ptr<T> class that instead of calling the object's functions on operator->, it could return std::optional<T&> (much like Rust) for which we can then safely call or deal with the std::nullopt case. Isn't there something already in C++? Or can it be implemented easily?
You haven't shown need for either pointers or optionals here.
MyClass myClassSafe;
myClassSafe.someFunction();
No possibility of null pointers or empty optionals in sight.
optional<T> allows you to handle the "no T available" case, which shared_ptr<T> already handles. Therefore optional<shared_ptr<T>> is redundant, just like optional<optional<T>> is.
There is a case to be made for shared_ptr<optional<T>> - if one owner creates the T object, the other owner can see the new object, so that isn't really redundant.
Your use of std::optional here is the cause of the problem. std::shared_ptr defines operator bool as a null pointer check, but because you have wrapped it in std::optional this never gets called
If instead you try:
MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
// std::shared_ptr implements operator bool as a null pointer check
myClass->someFunction();
} else {
//do something in case no value
}
Isn't there something already in C++?
There is nothing in std to handle non null smart pointer.
As Caleth shows in his answer, you can use object directly and avoid (smart) pointer and std::optional.
Or can it be implemented easily?
Non null smart pointer (a "smart reference" :) ) should be non default constructible, and "non-movable" (I mean move should not invalidate the reference).
You could implement it with existing smart pointer, something like:
template <typename T>
class unique_ref
{
public:
// Avoid variadic constructor which might take precedence over regular copy/move constructor
// so I use tag std::in_place_t here.
template <typename ... Ts>
unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}
unique_ref(const unique_ref&) = delete;
unique_ref(unique_ref&&) = delete;
unique_ref& operator=(const unique_ref&) = delete;
unique_ref& operator=(unique_ref&&) = delete;
const T& operator*() const { return *ptr; }
T& operator*() { return *ptr; }
const T* operator ->() const { return ptr.get(); }
T* operator*() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
return {std::in_place, std::forward<Ts>(args)...};
}
unique version is not much useful, as non-copyable, non-movable. using directly T seems simpler.
shared version is copyable (its move should do identical to the copy)
A weak version might return an std::optional<shared_ref<T>>.

Emulate copy-assignment operator for lambdas in C++

This question has two parts
Firstly, can someone explain the rationale behind C++ disabling the copy-assignment operator for lambdas? If you're going to allow the copy constructor, why not the copy-assignment operator?
Secondly, how do you best overcome this limitation without forcing people to write C++03 style functors, or using std::function (the functions I'm dealing with are tiny, and I'd like the compiler to inline them wherever possible)?
Background:
I'm trying to implement a flat_map like operation in a stream processing library I'm writing, similar to flatMap in Scala or other functional languages. As a result, I need to create an iterator that iterates over a list of iterators. Each time the flat_map iterator is de-referenced a lambda associated with the inner iterator is executed. The outer iterator needs to switch the inner iterator each time the inner iterator reaches the end. Since the inner iterator contains a lambda, and therefore does not have a copy-assignment operator, it's not possible to switch it. Technically I could solve the problem using dynamic allocation, so that I always call the copy-constructor, but that doesn't seem like the right approach. Here is a snippet of code that might help highlight the problem:
template <typename Iter>
class flat_map_iterator {
public:
flat_map_iterator& operator++() {
++it_inner_;
if (it_inner_ == (*it_outer_).end()) {
++it_outer_;
// ERROR: cannot be assigned because its copy assignment operator is implicitly deleted
it_inner_ = (*it_outer_).begin();
}
return *this;
}
private:
Iter it_outer_;
typename Iter::value_type::iterator it_inner_;
};
Edit:
Thanks for the really quick responses. Here is a use case example:
int res = ftl::range(1, 4).map([](int a){
return ftl::range(a, 4).map([a](int b){
return std::make_tuple(a, b);
});
})
.flat_map([](std::tuple<int, int> x){ return std::get<0>(x) * std::get<1>(x); })
.sum();
assert(res, 25);
The ftl::range(begin, end) function returns a lazy iterator over the range [begin, end).
It's not that C++ disables the copy-assignment operator for lambda per-se, but that by default members in a lambda object are saved as const, and then the assignment operator can basically do nothing to assign to them, and so it is not generated. If you want lambdas to not hold members as const, you use the [...](...) mutable {...} syntax.
The other thing is that I'm not entirely sure what you get out of assigning lambdas. I mean, if you're going to re-use the lambda type (and functionality) and simply bind it to different variables, you're already working against the nice lambda capture syntax, and might as well have it be a normal function object. Assigning one type of lambda to another one is impossible. This means that you can not provide different lambda implementations when you hold the lambda itself by value.
If this is still what you're going for, I think dynamic allocation (e.g. using unique_ptr) is fair game.
And if you really want to avoid it, you could manually destruct and re-construct your lambda, as the following example illustrates:
#include <iostream>
template <class T>
struct LambdaContainer {
LambdaContainer(const T& lambda)
: lambda{lambda} {}
void resetLambda(const T& lambda) {
this->lambda.~T();
new (&this->lambda) T{lambda};
}
T lambda;
};
int main()
{
int i = 1;
auto l = [=]() {
std::cout << i;
};
using LT = decltype(l);
LambdaContainer<LT> lc{l};
lc.resetLambda(l);
}

Is there a way to make passing by reference, and passing by value explicit in the function call?

If you were to look at this code,
int x = 0;
function(x);
std::cout << x << '\n';
you would not be able to verify through any means of syntax, that parameter x is being passed by reference or that it's being passed by value. The only way you would know for sure, is if you looked at either the function declaration or function definition.
Here is a simple example of how I believe this could be a problem:
std::string Lowercase(std::string str); //<- this is hidden away in code; probably in a different file.
int main(){
std::string str = "HELLO";
Lowercase(str);
std::cout << str << '\n'; //<- Bug! we expected to output "hello". The problem is not very easy to spot, especially when a function name sounds as though it will change the passed in value.
}
In order to avoid having to jump between the function call and the function declaration (or in some cases, the documentation) in order to understand the function behavior, is there a way to explicitly document in the syntax of a function call that the parameter is expected to change (i.e. a reference parameter) or that a copy is being sent (i.e. pass by value)?
I realize that there is also the option of passing by const& which has the similar notion to passing by value, in that the variable passed in, will not have its value changed after the function call.
I'm sure there are all kinds of situations in the language that might add to the complexity of understanding how a parameter is being passed-
but I'm curious, is there a way to combat this problem in the way I want to?
I've noticed that some people write two similar functions. One of them takes a value parameter, the other one takes a pointer. That allows calling a function like this:
Lowercase(str); //we assume the value will not change
Lowercase(&str); //we assume the value will change
But this solution has many other issues, and I would not like to lose the benefit of references. Plus, we are still making assumptions on the behavior.
Some people insist that the correct way to pass mutable object is to use a pointer. That is, you would pass
Lowercase(&str);
... and Lowercase() would, obviously, be implemented to take a pointer. That approach may suit your needs.
I want to mention, however, that this is not what I would do! Instead, the approach I favor is to use appropriate names instead. For example,
inplace_lowercase(str);
pretty much says what it is going to do. Clearly, inplace_lowercase() would actually be an algorithm and with a bit of magic could be reasonably be called as
inplace_lowercase(str.begin() + 1, str.end());
as well.
Here are a few reasons why I don't like passing arguments by pointer and/or why I don't believe in an explicit indication of how the argument is passed:
Pointers can be null. A mandated reference parameters should, in my opinion, be a reference.
Passing by pointer still doesn't indicate whether the argument may be modified are not as the argument may be a T const*.
Having meaningful names makes it actually easier to understand what's going on in the first place.
Calling something without consulting its documentation and/or knowing what the called function will do doesn't work anyway and indicating how things are passed is trying to cure symptoms of a deeper problem.
I'm not sure I understand your requirements completely, but maybe this is something you can use:
template<typename T>
void foo( T ) { static_assert( sizeof(T)==0, "foo() requires a std::ref" ); }
void foo( std::reference_wrapper<int> t )
{
// modify i here via t.get() or other means of std::reference_wrapper
}
int main()
{
int i = 42;
// foo( i ); // does not compile, static_assert fires
foo( std::ref( i ) ); // explicit std::ref visible on the caller's side
}
Many (most) IDE's help you with this problem by displaying the function/method prototype(s) once they figure out which function you are calling.
This is C++: the lack of in and out parameters doesn't mean the language is deficient, it means you need to implement what other languages would do as a language feature as a library.
Create two template classes and functions.
in_param<T> is a wrapper around a T const&, whilie io_param<T> is a wrapper around a T& reference. You construct them by calling helper functions in and io.
Inside, they behave like references (via overloading).
Outside, the caller must call in or io on the argument, marking it up at the call site.
out is trickier: inside the fumction, only assignment is legal. Ideally we would not even construct it: an emplace method might help.
However, the caller needs some channel to know if the parameter was constructed or not.
What I would do is out_param only has operator=, and it assigns. out wraps something into an out_param. If you want delayed constructuon, use optional inside the out param, which gets close. Maybe out_param also has emplace, which usually just assigns, but if the tyoe wrapped has emplace calls it instead?
template<typename T>
struct in_param : std::reference_wrapper<T const> {
explicit in_param( T const& t ):std::reference_wrapper<T const>(t) {}
in_param( in_param<T>&& o ):std::reference_wrapper<T const>(std::move(o)) {}
void operator=( in_param<T> const& o ) = delete;
};
template<typename T>
struct io_param : std::reference_wrapper<T> {
explicit io_param( T& t ):std::reference_wrapper<T>(t) {}
io_param( io_param<T>&& o ):std::reference_wrapper<T>(std::move(o)) {}
};
template<typename T>
in_param< T > in( T const& t ) { return in_param<T>(t); }
template<typename T>
io_param< T > io( T& t ) { return io_param<T>(t); }
template<typename T>
struct out_param {
private:
T& t;
public:
out_param( T& t_ ):t(t_) {}
out_param( out_param<T>&& o ):t(o.t) {}
void operator=( out_param<T> const& o ) = delete;
void operator=( out_param<T> && o ) = delete;
void operator=( out_param<T> & o ) = delete;
void operator=( out_param<T> && o ) = delete;
template<typename U>
out_param<T>& operator=( U&& u ) {
t = std::forward<U>(u);
return *this;
}
// to improve, test if `t` has an `emplace` method. If it does not,
// instead do t = T( std::forward<Us>(us)... ). (I'd use tag dispatching
// to call one of two methods)
template<typename... Us>
void emplace( Us&&... us ) {
t.emplace( std::forward<Us>(us)... );
}
};
template<typename T>
out_param<T> out( T& t ) { return out_param<T>(t); }
or something like the above.
You now get syntax like:
void do_stuff( int x, in_param<expensive> y, io_param<something> z, out_param<double> d );
int main() {
expensive a;
something b;
double d;
do_stuff( 7, in(a), io(b), out(d) );
}
and failure to call in, io or out at the call site results in compile time errors. Plus, out_param makes it quite difficult to accidentally read the state of the out variable within the function, producing some very nice documentation at the call site.
If you use MS VC++ then maybe it will be useful information about source-code annotation language (SAL)
http://msdn.microsoft.com/ru-ru/library/hh916383.aspx
I think it's something useless to notify (by language nonetheless [1]). The only needed question is : "Is my object is semantically modified ?", and so :
When you read a prototype you know if a function could modify an object (non-const ref) or not (copy or const ref).
When you use a function (even without reading [2] the prototype) if you have to be sure to not modify an object, use a const_cast.
[1] A static analyzer could do it for its purposes.
[2] If you miss, the compiler would warn you anyway.
That is the whole point of pass-by-reference -- that syntactically don't need to do anything different from passing by value.

How to capture a unique_ptr into a lambda expression?

I have tried the following:
std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
//The caller given ownership of psomething
return [psomething](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
But it does not compile. Any ideas?
UPDATE:
AS suggested, some new syntax is required to explicitly specify we need to transfer the ownership to the lambda, I am now thinking about the following syntax:
std::function<void ()> getAction(std::unique_ptr<MyClass> psomething){
//The caller given ownership of psomething
return [auto psomething=move(psomething)](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
Would it be a good candidate?
UPDATE 1:
I will show my implementation of move and copy as following:
template<typename T>
T copy(const T &t) {
return t;
}
//process lvalue references
template<typename T>
T move(T &t) {
return std::move(t);
}
class A{/*...*/};
void test(A &&a);
int main(int, char **){
A a;
test(copy(a)); //OK, copied
test(move(a)); //OK, moved
test(A()); //OK, temporary object
test(copy(A())); //OK, copying temporary object
//You can disable this behavior by letting copy accepts T &
//test(move(A())); You should never move a temporary object
//It is not good to have a rvalue version of move.
//test(a); forbidden, you have to say weather you want to copy or move
//from a lvalue reference.
}
This issue is addressed by lambda generalized capture in C++14:
// a unique_ptr is move-only
auto u = make_unique<some_type>(some, parameters);
// move the unique_ptr into the lambda
go.run([u = move(u)]{do_something_with(u);});
You cannot permanently capture a unique_ptr in a lambda. Indeed, if you want to permanently capture anything in a lambda, it must be copyable; merely movable is insufficient.
This could be considered a defect in C++11, but you would need some syntax to explicitly say that you wanted to move the unique_ptr value into the lambda. The C++11 specification is very carefully worded to prevent implicit moves on named variables; that's why std::move exists, and this is a good thing.
To do what you want will require either using std::bind (which would be semi-convoluted, requiring a short sequence of binds) or just returning a regular old object.
Also, never take unique_ptr by &&, unless you are actually writing its move constructor. Just take it by value; the only way a user can provide it by value is with a std::move. Indeed, it's generally a good idea to never take anything by &&, unless you're writing the move constructor/assignment operator (or implementing a forwarding function).
The "semi-convoluted" solution using std::bind as mentioned by Nicol Bolas is not so bad after all:
std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething)
{
return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); },
std::move(psomething));
}
A sub-optimal solution that worked for me was to convert the unique_ptr to a shared_ptr and then capture the shared_ptr in the lambda.
std::function<void()> getAction(std::unique_ptr<MyClass> psomething)
{
//The caller given ownership of psomething
std::shared_ptr<MyClass> psomethingShared = std::shared_ptr<MyClass>(std::move(psomething));
return [psomethingShared]()
{
psomethingShared->do_some_thing();
};
}
I used this really dodgy workaround, which involves sticking the unique_ptr inside a shared_ptr. This is because my code required a unique_ptr (due to an API restriction) so I couldn't actually convert it to a shared_ptr (otherwise I'd never be able to get my unique_ptr back).
My justification for using this abomination is that it was for my test code, and I had to std::bind a unique_ptr into the test function call.
// Put unique_ptr inside a shared_ptr
auto sh = std::make_shared<std::unique_ptr<Type>>(std::move(unique));
std::function<void()> fnTest = std::bind([this, sh, input, output]() {
// Move unique_ptr back out of shared_ptr
auto unique = std::move(*sh.get());
// Make sure unique_ptr is still valid
assert(unique);
// Move unique_ptr over to final function while calling it
this->run_test(std::move(unique), input, output);
});
Now calling fnTest() will call run_test() while passing the unique_ptr to it. Calling fnTest() a second time will result in an assertion failure, because the unique_ptr has already been moved/lost during the first call.
One also need to know, that lambdas capturing unique_ptr cannot be converted into std::function because std::function requires that the callable object is copyable.
auto lambdaWithoutCapture = [](){return 1;}; //Can be std::function
auto lambdaWithCapture = [=](){return 1;}; //Can be std::function
auto lambdaWithCapture2 = [&](){return 1;}; //Can be std::function
auto lambdaWithCapture3 = [uptrProblematic = std::move(uptrProblematic)]() mutable {return 1;}; //Can't be std::function
Therefore, if you don't have to specify return type of the function, you can use such approach which does not use std::function. But you need to know, that this will only work in local scope. You can't declare auto workerFactory(); in header file, as this will raise compilation error.
auto workerFactory()
{
std::unique_ptr uptrProblematic = std::make_unique<int>(9);
int importantData = 71;
return [=, uptrProblematic = std::move(uptrProblematic)](std::string input) mutable -> int {
std::cout << "Problematic variable is equal to: " << *uptrProblematic << "\n";
std::cout << "Important data is equal to: " << importantData << "\n";
std::cout << "Input equal to: " << input << "\n";
return 9;
};
}
int main()
{
auto worker = workerFactory();
worker("Test");
}

std::list< std::unique_ptr<T> >: passing it around

Say I have a std::list of class T's:
std::list<T> l;
When passing it into functions, I would use a reference:
someFunction( std::list<T> &l )
What is the best way to pass around (the elements) of a std::list of unique_ptrs?
std::list< std::unique_ptr<T> > l;
Like this:
someFunction( std::unique_ptr<T> ptr )
Or this:
someFunction( T* ptr )
Or this:
someFunction( T &ref )
And what how would I call it using the std::list's back() function for example? These are IMHO all "kind of" equivalent, but I'm sure I'm missing something here.
Thanks
In order of best to worse:
someFunction(const T&);
someFunction(T&);
someFunction(const std::unique_ptr<T>&);
someFunction(std::unique_ptr<T>&);
The first one is the best because it does not modify the object it and it will work with the object no matter how you have allocated it (for example, you could switch to shared_ptr with no problems).
Number two will also work regardless of what smart pointer you are using; however, it assumes that you can modify the object, and whenever you can make something const, you should.
Numbers 3 and 4 both allow the object being pointed-to to be mutated; however, #3 does not allow the smart pointer to be modified, while number 4 does. Both have the disadvantage that they force the use of unique_ptr, whereas the two above it would work regardless of smart pointer class.
Passing a unique_ptr by value, as you have in some of the other examples is not an option; a unique_ptr is supposed to be unique. If you are copying it, consider using shared_ptr.
For the first two, if you invoked it on the result of back(), it would look like:
someFunction(*(lst.back())); // dereference lst.back() before passing it in.
For the latter two, if you invoked it on the resut of back(), it would look like:
someFunction(lst.back()); // pass the smart pointer, not the object to
// which the smart pointer currently points.
Do not pass unique_ptr by value, first of all it won't compile without a std::move and if you do use std::move it will empty the value you have stored in your list and you won't be able to access it any more.
This is because unique_ptr is not copyable, it doesn't have a copy constructor of type unique_ptr::unique_ptr(const unique_ptr<T>& other) instead it only has a move constructor (unique_ptr::unique_ptr(unique_ptr<T>&& source)).
unique_ptr and also classes / instances containing unique_ptr can be used in std::list (and other containers), provided that they have move constructor class_name(class_name &&) defined (which unique_ptr, of course, has).
When you pass around those elements, you're always moving (and not copying) them, so you always use std::move() on lvalues, like in
my_list.push_back(std::move(my_element));
this makes visible that you're passing (= moving) the element into the list, and that my_element is "empty" (like empty unique_ptr) after that operation.
Example:
typedef std::unique_ptr<uint8_t[]> data_ptr;
class data_holder
{
private:
int something_about_data;
data_ptr data;
public:
data_holder(data_ptr && _data)
: data(std::move(_data))
{}
// hey compiler, please generate a default move constructor for me
// despite of present destructor
data_holder(data_holder &&) = default;
~data_holder()
{
// ...
}
bool is_empty() const { return ! bool(data); }
}
// ...
{
// ...
data_holder the_element(data_ptr(new uint8_t[DATA_SIZE]));
// move the_element into the_list
the_list.push_back(std::move(the_element));
if (the_element.is_empty())
std::cerr << "data_holder 'the_element' is now empty!" << std::endl;
// ...
}