I want to be able to share a variable in the containing scope between two lambda functions. I have the following:
void holdAdd(const Rect& rectangle, Hold anonymousHeld, Hold anonymousFinish) {
std::map<int,bool> identifierCollection;
HoldFinish holdFinish = [=](const int& identifier) mutable {
if (identifierCollection.count(identifier) == 0) return;
identifierCollection.erase(identifier);
anonymousFinish();
};
holdCollisionCollection.push_back([=](const int& identifier, const Vec2& point) mutable {
if (rectangle.containsPoint(point)) {
identifierCollection[identifier] = true;
anonymousHeld();
} else {
holdFinish(identifier);
}
});
holdFinishCollection.push_back(holdFinish);
}
I can see in the debugger that holdFinish is pointing to a different implementation of identifierCollection than in the 2nd lambda function.
If I use [=, &identifierCollection] it throws a EXC_BAD_ACCESS whether I use mutable or not.
My experience with other languages that implement inline functions is that this should be possible. For instance in javascript:
var a = 10;
var b = function() {
a += 2;
}
var c = function() {
a += 3;
}
b();
c();
alert(a);
Would alert 15.
What do I have to do to get both lambda functions to reference the same identifierCollection implementation? So that it behaves in the same way as the javascript example.
Unlike in some scripting languages, identifierCollection's lifetime won't be extended simply because you captured it into a closure. So as soon as you change that [=] for a [&] to capture by reference, it's a dangling reference to a local variable that you're capturing.
You'll have to manage the lifetime of identifierCollection yourself; frankly, this sounds like the perfect opportunity for a shared pointer, captured by value into each lambda. The dynamically-allocated map it wraps will literally exist for as long as you need it to.
void holdAdd(const Rect& rectangle, Hold anonymousHeld, Hold anonymousFinish)
{
auto identifierCollection = std::make_shared<std::map<int,bool>>();
HoldFinish holdFinish = [=](const int& identifier) mutable {
if (identifierCollection->count(identifier) == 0) return;
identifierCollection->erase(identifier);
anonymousFinish();
};
holdCollisionCollection.push_back([=](const int& identifier, const Vec2& point) mutable {
if (rectangle.containsPoint(point)) {
(*identifierCollection)[identifier] = true;
anonymousHeld();
} else {
holdFinish(identifier);
}
});
holdFinishCollection.push_back(holdFinish);
}
If you wrap the map in a std::shared_ptr then the lifetime will be managed automatically. Your lambda can then capture by value and it will get a reference to the map whose lifetime remains valid until the lambda function returns.
To do this, change your map definition to:
auto identifierCollection = std::make_shared<std::map<int,bool>>();
And then any calls to member functions of the map need to change from using . to -> (as it is now a pointer).
Related
I have a situation where I need to assign a unique ptr value from within a lambda function.
std::unique_ptr<SomeType> unique_ptr_obj;
// Lambda below has fixed return type.
bool var = ()[unique_ptr_obj=std::move(unique_ptr_obj)]-> bool {
unique_ptr_obj = GetUniqueObject();
return true
} ();
// Should be able to use unique_ptr_obj
UseUniqueObject(unique_ptr_obj.get());
However, as expected unique_ptr_obj is nullptr as it was moved into lambda. Is there a way I can populate unique_ptr_obj from within a lambda and be able to reuse it later ?
Any suggestions on how to accomplish this ? Should I convert unique_ptr_obj to shared_ptr ?
You should change the declaration of your lambda to capture unique_ptr_obj by reference:
bool var = [&unique_ptr_obj]() -> bool {
// Whatever the next line does, now it changes that variable by reference.
// Otherwise you were changing a local copy.
unique_ptr_obj = GetUniqueObject();
return true;
} ();
You don't want to share ownership. Or maybe you do, but it won't help with the lambda assigning something to unique_ptr_obj, hence using a shared_ptr is not the solution.
You also do not want to move from unique_ptr_obj. Sloppy speaking, moving from something means leaving it in an empty state.
If you want a function to modify its argument then you pass by reference. If you want a lambda to modify something in the outer scope you let it capture it by reference.
This is the same whether its an int or a unique_ptr:
int x = 0;
bool value = [&x]() { x = 42; return true; } ();
// ^^ capture x by reference
assert(x == 42);
I want to return a boolean or success/failure enum from the function and modify an argument by reference. However, I want to construct a reference in the calling function instead of copying the value.
I have some container (say 'example_q' of type std::queue). queue.front() will return a reference to the value stored in the queue. I can make a copy of that reference (example A) or I can take a reference of that reference (example B), allowing the value to stay in the queue but be utilized outside of it.
A)
int a = example_q.front();
B)
int& b = example_q.front();
Using this difference I could also return the queued value:
A)
int get_front()
{
int a = example_q.front();
return a;
}
B)
int& get_front()
{
return example_q.front();
}
Using option 'B' I can avoid unnecessary copies without moving the data out of the queue via std::move() semantics.
My question is, can I do 'B' via an argument passed by reference? Would I need to use std::move()/rvalues/&& somehow?
void get_front(int& int_ref)
{
// somehow don't copy the value into referenced int_ref, but construct
// a reference in the caller based on an input argument?
int_ref = example_q.front();
}
The problem this would solve is making API match other functions that modify reference arguments but return a success/failure value, ie:
if(q.get_front(referrence_magic_here))
{
...
}
I could reverse the order to get the desired result, IE:
int& get_front(bool& success)
{
...
}
But I'd rather keep the pattern of my API as well as being able to do it via a single line in the if() statement if possible.
Perhaps something like:
bool get_front(int&& int_rvalue)
{
...
int_rvalue = example_q.front();
...
return true_or_false;
}
void calling_func()
{
...
if(get_front(int& magical_ref))
{
... //use magical_ref here?
}
...
}
No, you can't do that.
Other than in its initialiser, a reference behaves like the thing it refers to. By passing it as a function argument, you "hide" the initialiser from the part that wants to do the assignment. So, the function has no access to the referencey behaviour of the thing.
You will have to use pointers if you want to do that:
void get_front(int*& int_ptr)
{
int_ptr = &example_q.front();
}
int* ptr = nullptr;
get_front(ptr);
// optional:
int& ref = *ptr;
(Ew!)
Option B was fine.
This code is invalid C++:
if(get_front(int& magical_ref))
You cannot declare a new variable as you're passing it to a function. And because a reference variable must be declared and initialized at the same time, it wouldn't be possible to have a reference be initialized by passing it to a function.
You could however, do this:
if(int &magical_ref = get_front()) {
But note that you'd be checking whether magical_ref is 0 or not, which is different from the condition you have in your example.
If your logic is as simple as comparing the int, you could do:
if (int& magical_ref = get_front(); magical_ref == 42)
You can return a std::tuple<int&, /* status condition */> and check the status. For example:
std::tuple<int&, bool> get_front() {
static int example = 0;
return {example, false};
}
...
// C++17's structured bindings + if statement with initializer
if (auto [ref, success] = get_front(); success) {
ref = 42;
}
Demo
What is the idiomatic C++ way of doing this?
I have a method which looks like this:
LargeObject& lookupLargeObject(int id) {
return largeObjects[id];
}
This is wrong, because if you call this with a non-existent id it will create a new instance of large object and put it into the container. I don't want that. I don't want to throw an exception either. I want the return value to signal that object wasn't found (as it is a more or less normal situation).
So my options are either a pointer or an optional. Pointer I understand and like, but it feels like C++ doesn't want to me use pointers any more.
So on to optionals. I will return an optional and then the caller looks like this:
std::optional<LargeObject> oresult = lookupLargeObject(42);
LargeObject result;
if (oresult) {
result = *oresult;
} else {
// deal with it
}
Is this correct? It feels kind of crappy because it seems that I'm creating 2 copies of the LargeObject here? Once when returning the optional and once when extracting it from optional into result. Gotta be a better way?
Since you don't want to return a pointer, but also don't want to throw an exception, and you presumably want reference semantics, the easiest thing to do is to return a std::optional<std::reference_wrapper<LargeObject>>.
The code would look like this:
std::optional<std::reference_wrapper<LargeObject>> lookupLargeObject(int id) {
auto iter = largeObjects.find(id);
if (iter == largeObjects.end()) {
return std::nullopt;
} else {
return std::ref(iter->second);
}
}
With C++17 you can even declare the iter variable inside the if-condition.
Calling the lookup function and using the reference then looks like this (here with variable declaration inside if-condition):
if (auto const lookup_result = lookupLargeObject(42); lookup_result) {
auto& large_object = lookup_result.value().get();
// do something with large_obj
} else {
// deal with it
}
There are two approaches that do not require use of pointers - using a sentinel object, and receiving a reference, instead of returning it.
The first approach relies on designating a special instance of LargeObject an "invalid" one - say, by making a member function called isValid, and returning false for that object. lookupLargeObject would return that object to indicate that the real object was not found:
LargeObject& lookupLargeObject(int id) {
if (largeObjects.find(id) == largeObjects.end()) {
static LargeObject notFound(false);
return notFound;
}
return largeObjects[id];
}
The second approach passes a reference, rather than receiving it back:
bool lookupLargeObject(int id, LargeObject& res) {
if (largeObjects.find(id) == largeObjects.end()) {
return false;
}
res = largeObjects[id];
return true;
}
If default constructed LargeObject is unwanted from lookupLargeObject, regardless of whether it is expensive or it does not make semantic sense, you can use the std:map::at member function.
LargeObject& lookupLargeObject(int id) {
return largeObjects.at(id);
}
If you are willing to live with use of if-else blocks of code in the calling function, I would change the return type of the function to LargeObject*.
LargeObject* lookupLargeObject(int id) {
auto it = largeObjects.find(id);
if ( it == largeObjects.end() )
{
return nullptr;
}
return &(it->second);
}
Then, client code can be:
LargeObject* result = lookupLargeObject(42);
if (result) {
// Use result
} else {
// deal with it
}
I am implementing a member function called CurrentUser. It will take a username as parameter and return the User instance object which matches the given username. Below is the code
User& UserDB::currentUser(string username){
// userlists is a instance member which is list of user objects
for(list<User>::iterator i = userlists.begin(); i != userlists.end(); ++i)
{
if(*i.getName().compare(username)==0){
return *i;
}
}
return null;
}
Not sure if it is the correct way to do so. Correct me if it is wrong. Thanks!
Update:
hey guys thanks for your advice, i figure out a way to do so by returning a User pointer. Here is the code.
User* UserDB::currentUser(string username){
for(list<User>::iterator i = userlists.begin(); i != userlists.end(); ++i)
{
if(i->getName().compare(username)==0){
return i;
}
}
return null;
}
there are a couple of ways to do this cleanly.
You can of course return a pointer, but that will be surprising to people as it is more normal to return a reference or an object. pointers present object consumers with a number of problems, e.g.:
what should I conclude if it's null?
should I delete it?
and so on.
Returning a reference to something or a something removes these ambiguities.
Having said that, references cannot be empty, so the function must return something. If it does not find the item it's looking for, it must indicate that to the caller. One way is an exception (i.e. it was logically incorrect to ask for that item). However, if the item not being there is a normal occurrence, then you don't want to force your consumers to handle exceptions - that's bad form too.
So the answer is to return an object that encapsulates an optional reference.
A good example of this is boost::optional<User&> but if you don't want to include boost it's fairly simple to roll your own:
struct optional_user
{
using element_type = User;
using reference_type = element_type&;
optional_user() : _p(nullptr) {}
optional_user(reference_type r)
: _p(std::addressof(r))
{}
bool valid() const { return bool(_p); }
// compares to true if the user is present, false otherwise
operator bool() const { return valid(); }
reference_type value() const {
assert(_p);
return *_p;
}
// can be used anywhere a User& is required
operator reference_type () const {
return value();
}
private:
element_type* _p = nullptr;
};
now your function becomes:
optional_user UserDB::currentUser(string username)
{
typedef list<User>::iterator Iter;
for(Iter i = userlists.begin(); i != userlists.end(); ++i)
{
if(i->getName().compare(username)==0)
{
return optional_user(*i);
}
}
// return an indicator that the user is not present
return optional_user();
}
and your call site becomes:
optional_user = users.currentUser("bob");
if (optional_user) {
do_something_with(optional_user /* .value() */);
}
If you want to specifically return a reference, the item you are referring to must have a lifetime after execution leaves the function.
There are several alternatives:
static local variable in function
using dynamic memory
variable declared outside function
Pass by non-const reference
Here is an example of #1:
const std::string& Get_Model_Name(void)
{
static const std::string model_name = "Accord";
return model_name;
}
Other alternatives are to return a variable by value (copy). This doesn't use references. A copy is returned.
For example:
std::string Get_Manufacturer_Name(void)
{
return std::string("Honda");
}
You may also consider passing by parameter and modifying the parameter:
void Get_Lunch_Special_Name(std::string& entree_name)
{
entree_name = std::string("Beef Wellington");
}
I've just been doing some experimenting recently with functional reactive programming and what it is, and when i was trying to implement something like it in c++, i turned to the lambda for some help. I came up with the beginnings of something like this,
template<class T>
class Reactive
{
public:
Reactive(T data)
{
m_Data = data;
}
Reactive(std::function<T()> func, T data)
{
m_Data = data;
m_Affecter = func;
}
template<class H>
Reactive & operator+(const H & rhs)
{
m_Data += rhs;
return *this;
}
template<class H>
Reactive operator+(Reactive<H> & rhs)
{
std::function<decltype(m_Data + rhs.m_Data)()> func;
if (!rhs.m_Affecter)
func = [&](){return m_Data + rhs.m_Data;};
else
func = [&](){return m_Data + rhs.m_Affecter();};
return Reactive<decltype(m_Data + rhs.m_Data)> (func, m_Data + rhs.m_Data);
}
Reactive & operator=(const T & data)
{
m_Data = data;
return *this;
}
Reactive & operator=(const Reactive & rhs)
{
m_Data = rhs.m_Data;
m_Affecter = rhs.m_Affecter;
return *this;
}
T & Get()
{
return m_Data;
}
void Update()
{
m_Data = m_Affecter();
}
private:
std::function<T()> m_Affecter;
T m_Data;
};
It only support addition thus far. i was trying to make an object called a reactive that can wrap around any other type, except that when a math operation is performed on it, a lambda is created, where that operation takes place, so as to kind of remember what has been done to it before, and to do it again when one of it's affecting values has changed, (after calling the update function). for example if i were to do this.
Reactive<int> cheh = 0;
Reactive<int> meh = 3;
Reactive<int> peh = 7;
cheh = meh + peh;
meh = meh + 4;
cheh.Update();
std::cout << cheh.Get();
then heres what would take place. summing the two Reactives in line five would make another Reactive with their two values added to 10 as well as set it's affector to a lambda that does something like this, &{meh.m_Data + peh.m_Data} . Then that Reactive would be assigned to cheh. When the value m_meh had 4 added to it, and cheh was updated, it's affector was called with the new value of 14 and that is what is printed to the screen, exactly as i'd intended.
But then i got to thinking, what if one of those Reactives that takes part in cheh's affecter goes out of scope. The program should error out, if not handled correctly.
So i did this,
Reactive<int> cheh = 0;
Reactive<int> meh = 3;
{
Reactive<int> peh = 7;
cheh = meh + peh;
peh = peh + 4;
}
cheh.Update();
std::cout << cheh.Get();
At the point when update is called, the Reactive peh that took place in his affecter has gone out of scope and no longer exists. However, this program and cheh's affecter execute successfully and it prints out 14 just as before. I know that the values in the lambda were passed in by the reference capture, so how can the affecter function still access the reference to peh? Does an object or integral type passed into a lambda by reference force them to persist as long as the lambda exists? Something smell's fishy...
I know that the values in the lambda were passed in by the reference capture, so how can the affecter function still access the reference to peh? Does an object or integral type passed into a lambda by reference force them to persist as long as the lambda exists? Something smell's fishy...
The program has Undefined Behavior. Capturing by reference, as you suspect, does not prolong the lifetime of the objects those references are bound to, and dereferencing a reference to an object which no longer exists is UB.
However, Undefined Behavior does not necessarily mean that a crash will occur. It is possible (as seems to be the case here) that the program will just seem to work fine. This might not be true on another machine, or after you reboot your machine.
Also see this brilliant explanation of why it may seem that objects can be accessed even after they have fallen out of scope.