I have the following lambda
direction->addClickEventListener([=](Ref* sender){
std::unordered_map<int,int> data;
rep->getData(DIRECTION, data);
int last = data[1];
int rotation = (last + 45)%360;
LOG("l:%i r:%i",last,rotation);//Always logs l:0 r:45
direction->setRotation(rotation);
data[1] = rotation;
rep->setData(DIRECTION, data);
});
where getData is:
void getData(DATA_KEY key,std::unordered_map<int,int>& data){
//Modifies data with the appropriate values for key, for the current state of rep
}
void setData(DATA_KEY key,std::unordered_map<int,int>& data){
//Makes a copy of data stores it internally with key
}
rep is pointer, so I thought that whenever the lambda is called, the current value of data will always reflect the current state of rep. But it seems that it is always the value of whatever rep was at the time direction->addClickEventListener was called.
If I want to use the current state of rep, how ghouls I modify my lambda ?
EDIT: Since rep is a pointer, I can't can't capture by reference..
I'm not really sure what you're asking, so this might not be an answer to your problem, but it is an attempt to clarify what the problem with capturing by reference is.
It looks like you are having an event-based system. The important thing to know about events is that they can occur at any time.
Now lets say you have something like this (very simplified and pseudo-ish):
void some_function(some_type* rep)
{
add_event_listener([&]()
{
do_something(rep);
});
}
There is a very serious bug in the code above: When the event is invoked and the lambda is called, the function some_function will have returned, and therefore the scope of the local variable rep doesn't exist any more. So when rep is used in the lambda it is a reference to a variable that doesn't exist anymore (remember that rep is a local variable). That of course leads to undefined behavior.
If you capture by value instead, the pointer is copied meaning you now have two pointer variables, both pointing to the same memory. Then it doesn't matter if the first variable goes out of scope, because the second variable still is valid.
Pointer doesn't have state, methods or something. Pointer is abstract address of storage where your object is. "Reference" is synonymous to pointer in some ways, if you think in C terms, but they are different in C++ - you can pass pointer variable by reference, thus passing control over its value (not over the state of object it points to, that actually achieved by pointer). Pointer variable is also a storage, that contains value of pointer
You can pass any variable (storage) "by reference", which means that function can change value stored in that variable. In C that was done by passing pointers, but to pass pointer "by reference" they had to pass type like void** pointer to a pointer. In C++ & syntax is used to reduce the clutter.
[=] mans that all external variables are captured by value. This would allow anonymous function to read value of pointer, deference it and call methods\access fields of the objects it points to.
[&] would mean capture by reference. Pointer is variable. This would allow lamba to modify it, making it to point to other object.
If you do need only rep by reference use, [=. &rep].
How rep might be changed while lambda is running? If that happens in parallel thread, you'll probably need an atomic.
If you cannot change actual object your pointer refers to, that may mean that compiler does aliasing optimization because of illegal cast from one object to another, because casted away const modifier or low quality of implementation (that's rare) that causes aliasing optimization where it should not happen.
Related
Zap initializes its default option struct as follows in its grpc interceptor:
var (
defaultOptions = &options{
levelFunc: DefaultCodeToLevel,
shouldLog: grpc_logging.DefaultDeciderMethod,
codeFunc: grpc_logging.DefaultErrorToCode,
durationFunc: DefaultDurationToField,
messageFunc: DefaultMessageProducer,
timestampFormat: time.RFC3339,
}
)
And the later zap performs a copy of values:
*optCopy = *defaultOptions
What is the purpose of declaring the variable defaultOptions as a pointer and then later dereferencing it for copying? I was wondering if there is any issue with not using pointer:
defaultOptions = options{
levelFunc: DefaultCodeToLevel,
shouldLog: grpc_logging.DefaultDeciderMethod,
codeFunc: grpc_logging.DefaultErrorToCode,
durationFunc: DefaultDurationToField,
messageFunc: DefaultMessageProducer,
timestampFormat: time.RFC3339,
}
optCopy = &options{}
*optCopy = defaultOptions
A possible advantage with using a pointer is that you can then have that pointer set to nil; obviously if it is nil, you can't dereference it; but this might be used to indicate that there are no options and there may be code to handle this.
Caveat: I am not a Go programmer.
My guess, based on previous issues I had with big systems, is that with configuration structs, if for any reason some part of your software changes the value of something, that change will propagate to any function/member who has that pointer, and most of the times you don't want that to happen, you usually want that the configuration that you probably read from a file, stays the same, even if some function needs to do a transformation of a specific field of the struct holding that configuration.
So basically, you keep the original struct fresh, but you can send the pointer around to have its contents copied anywhere.
That's my educated guess, it is most likely an application architecture decision.
Edit: After further pondering:
If the author of the code had in his mind the idea of moving that data structure everywhere in his code, in multiple levels deep and broad, declaring it as value would mean he would have to copy it every time he wanted to move the data from function to function, or that the data structure could be erased by the end of execution of scope, whereas with a pointer he can move only the pointer around (much faster) and then only copy the data once the pointer arrives at the destination function.
I have the following code. https://play.golang.org/p/YAa6cgtA3Vo
The address of the receiver pointer varies between method calls. This is perplexing. Can anyone explain why this is the case? Do I need to pass a pointer to a receiver as an argument in order to maintain the same address?
type myStruct struct {
//struct content is irrelevant
}
func (ptrToStruct *myStruct) returnAddress() **myStruct {
return &ptrToStruct
}
func (ptrToStruct *myStruct) method1() {
addressOfPtr := ptrToStruct.returnAddress()
fmt.Println(&ptrToStruct)
fmt.Println(addressOfPtr)
if &ptrToStruct != addressOfPtr {
fmt.Println("Different addresses!")
}
}
EDIT:
What I want is the address of ptrToStruct and not its value. I know that I could just get it in method1() by typing addressOfPtr = &ptrToStruct but in my use case I have some logic happening in the returnAddress() method and I need it to come from there.
That's simple: when you have var ms myStruct somewhere,
calling ms.returnAddress() would pass the address of the ms variable to returnAddress, and that address would always be the same (this is easily verifyable — try it itself).
Now consider that the ptrToStruct in the returnAddress definition is just a special argument to be passed to that method, and it has a concrete type — *myStruct.
This type internally is just an integer — large enough to store an address of any memory location on your platform/OS combination.
Now consider that when the call ms.returnAddress() is performed, the address of the ms variable is taken and written to the ptrToStruct argument passed to returnAddress. And that argument is also a variable — with the lifetime equal to the duration of the function call, and visible only in that function's body.
This variable is automatically created on the call stack by the code which prepares the function call.
(And the same happens to all the other method arguments.)
So, when you take the address of ptrToStuct, you take the address of a variable appeared at some location on the call stack which will be gone once the method returns.
Now consider that:
goroutine stacks in Go are growable (and hence may be relocated in memory when grown);
a method may be called from different goroutines (each has its own stack);
even if the method is called from the same goroutine multiple times, it may be called from different places in the code path executed by that goroutine.
All of the above may lead to the address of ptrToStruct variable being essentially random from call to call.
What you (probably) actually want is just returning the value of ptrToStruct as is, not its address.
If you feel like not really getting into how ptrToStruct springs into existence and vanishes, consider starting with this.
R.33 is confusing me. Can someone care to explain further? The meaning of "reseating" doesn't seem to work here. ??
R.33: Take a unique_ptr& parameter to express that a function reseats thewidget
Reason Using unique_ptr in this way both documents and enforces the function call’s reseating semantics.
Note “reseat” means “making a pointer or a smart pointer refer to a different object.”
Example
void reseat(unique_ptr&); // "will" or "might" reseat pointer
Example, bad
void thinko(const unique_ptr&); // usually not what you want
From the CPP guideline:
"reseat" means "making a reference or a smart pointer refer to a different object."
From modernescpp.com:
Let's look at each function signature in isolation. What does this
mean from the function perspective?
void share(std::shared_ptr<Widget> shaWid)
I'm for the lifetime of the function body a shared owner of the
Widget. At the begin of the function body, I will increase the
reference counter; at the end of the function, I will decrease the
reference counter; therefore, the Widget will stay alive, as long as I
use it.
void reseat(std::shared_ptr<Widget>& shaWid)
I'm not a shared owner of the Widget, because I will not change the
reference counter. I have not guaranteed that the Widget will stay
alive during the execution of my function, but I can reseat the
resource. A non-const lvalue reference is more like: I borrow the
resource and can reseat it.
void mayShare(const std::shared_ptr<Widget>& shaWid)
I only borrow the resource. Either can I extend the lifetime of the
resource nor can I reseat the resource. To be honest, you should use a
pointer (Widget*) or a reference (Widget&) as a parameter instead,
because there is no added value in using a std::shared_ptr.
Consider the following code snippet:
class Owner {
public:
Owner(std::unique_ptr<int> ptr) : owned_pointer<int>(std:move(ptr)) {}
private:
std::unique_ptr<int> owned_pointer;
};
std::unique_ptr<int> ptr(new int);
int* ptr1 = ptr.get();
Owner new_owner(std::move(ptr));
Is it safe to assume that ptr1 is valid as long as new_owner stays in scope? It seems to work, but I can't find a specification that states that explicitly - is it undefined behavior/implementation specific and just happen to work for me, or the code posted above is valid (ptr1 is guaranteed to point to moved pointer as long as it stays alive)?
Yes, the C++11 specification guarantees that transferring ownership of an object from one unique_ptr to another unique_ptr does not change the location of the object itself, and that get() on the second unique_ptr returns the same as it would have on the first unique_ptr before the transfer.
Looking at N3337, section 20.7.1:
Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following
postconditions hold:
u2.p is equal to the pre-transfer u.p,
u.p is equal to nullptr, and
if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
where u is a unique_ptr object that stores a pointer u.p.
The first bullet answers the question directly, since get() is specified as returning the u.p.
Yes, it is valid.
You can have multiple (plain) pointers pointing to the same object. The question is how long those pointers are valid or when the object pointed to is deleted.
A unique_ptr stores one more plain pointer and takes ownership, meaning it is responsible for when the object is destroyed. Moving it to another unique_ptr just transfers ownership, the object itself is still the same and all plain pointers pointing to it remain valid.
Only when the ownership is not transferred (or released) and the owning unique_ptr is destroyed, it also destroys the object. This would be the moment where all plain pointers pointing to the object become dangling pointers and dereferencing them would be illegal.
Is it legal/proper c++0x to leave an object moved for the purpose of move-construction in a state that can only be destroyed? For instance:
class move_constructible {...};
int main()
{
move_constructible x;
move_constructible y(std::move(x));
// From now on, x can only be destroyed. Any other method will result
// in a fatal error.
}
For the record, I'm trying to wrap in a c++ class a c struct with a pointer member which is always supposed to be pointing to some allocated memory area. All the c library API relies on this assumption. But this requirement prevents to write a truly cheap move constructor, since in order for x to remain a valid object after the move it will need its own allocated memory area. I've written the destructor in such a way that it will first check for NULL pointer before calling the corresponding cleanup function from the c API, so that at least the struct can be safely destroyed after the move.
Yes, the language allows this. In fact it was one of the purposes of move semantics. It is however your responsibility to ensure that no other methods get called and/or provide proper diagnostics. Note, usually you can also use at least the assignment operator to "revive" your variable, such as in the classical example of swapping two values.
See also this question