First of all, this is the most obscure problem I have ever had and thus is the hardest question to ask. I'll try make this question as articulate as possible by posting minimal code and providing some context. First of all here is the code where the problem occurs:
// Before lambda, pointer variable in question is fine
menu->onSelect = [=] ()
{
window->pushCallback('e', [=]()
{
// Here the pointer captured changes, causing a segfault later on
}
};
So now for some context:
The signature for pushCallback looks like this:
void Window::pushCallback(int key, std::function<void()> callback) {}
It stores a function to call when the key code denoted by the first argument is called, in this case 'e'.
Menu::onSelect is also a std::function, storing a single function to execute when a menu item is chosen.
Now the obscurity of this problem is that the pointer only changes on the second time stepping through the code. Note that this is an interactive ncurses program. However I have done much testing and have found the pointer changes between the two shown comment lines. Showing that the mutation occurs through capturing the variable in the nested lambdas. I have also made the pointer const in all classes that refer to it.
You cannot use automatic member capture in nested lambdas like that because the inner lambda's capture isn't performed until the outer lambda is executed. I believe that the are some differences between pre-C++14 and C++14/17 but I don't remember off-hand. I'll look into it and update my answer.
Also, I vaguely remember running into some differences between G++ and Clang, but that had to do with the compiler complaining, not with implementation differences that would cause a segfault. Again, I'll update once I can remember.
Work around, explicitly capture the variable or save it in a tmp variable.
std::shared_ptr<int> ptr; // This assumes that you are talking about shared pointers since I don't think you would have this problem with raw pointers unless the object is being destroyed before your lambda is being invoked
auto x = [ptr]()
{
// You could also create a temporary variable here to avoid ambiguity
// std::shared_ptr<int> ptr2;
return [ptr]() { return ptr; };
};
I verified that my original hypothesis is wrong. Shared points work properly in this case (but make sure you're not passing by reference or all bets are off).
auto foo(std::shared_ptr<int> p)
{
return [=](int x) { return [=](int y) { return *p + x + y; }; };
}
int main()
{
auto p = std::make_shared<int>(42);
auto func = foo(p);
std::cout << func(1)(2) << std::endl;
++(*p);
std::cout << func(1)(2) << std::endl;
return 0;
}
I recommend looking at the error in gdb and possibly setting a hardware break on the pointer if you are concerned that it is being changed.
Related
I'm trying to ensure an object - wrapped by a shared_ptr - is alive as long as a function is executed by passing it as value. However inside the function the object is not used at all, so I just want to use it for 'pinning':
void doSomething(std::shared_ptr<Foo>) {
// Perform some operations unrelated to the passed shared_ptr.
}
int main() {
auto myFoo{std::make_shared<Foo>()};
doSomething(std::move(myFoo)); // Is 'myFoo' kept alive until doSomething returns?
return 0;
}
I did check the behavior on different optimization-levels (GCC) and it seems that it works as intended, however I don't know whether the compiler still may optimize it away in certain scenarios.
You don't need to worry - the lifetime of the function argument at the call site is guaranteed to survive the function call. (This is why things like foo(s.c_str()) for a std::string s work.)
A compiler is not allowed to break that rule, subject to as if rule flexibility.
This very much depends on what the body of doSomething and Foo will actually look like. For instance, consider the following example:
struct X
{
~X() { std::cout << "2"; };
};
void f(std::shared_ptr<X>) { std::cout << "1"; }
int main()
{
auto p = std::make_shared<X>();
f(std::move(p));
}
This program has the very same observable effect as:
int main()
{
std::cout << "12";
}
and the order "12" is guaranteed. So, in the generated assembly, there may be no shared pointer used. However, most compilers will likely not perform such aggressive optimizations since there are dynamic memory allocations and virtual function calls involved internally, which is not that easy to optimize away.
The compiler could optimise away the copying of an object into a function argument if the function is being inlined and if the copying has no side effects.
Copying a shared_ptr increments its reference count so it does have side effects so the compiler can't optimise it away (unless the compiler can prove to itself that not modifying the reference count has no effect on the program).
I have an existing function:
void foo(const Key* key = nullptr)
{
// uses the key
}
I want to pass it pointer to temporary Key object (i.e. rvalue) like:
foo(&Key());
This causes compilation error, but is there a way in c++ 11/14 how I can do this? Of course I could do:
Key key;
foo(&key);
But I don't need object Key, I only need it inside foo() and foo()
Or I could do:
foo(new Key());
But then the object will not be deleted.
I don't think this is a good idea, but if you really really want a temporary and cannot change foo, you can cast the temporary to a const&:
int main()
{
foo(&static_cast<const Key&>(Key{}));
}
live example on wandbox
Alternatively, you could "hide" the creation of the object behind a convenient function:
template <typename T, typename F, typename... Ts>
void invoke_with_temporary(F&& f, Ts&&... xs)
{
T obj{std::forward<Ts>(xs)...};
f(&obj);
}
int main()
{
invoke_with_temporary<Key>(&foo);
}
live example on wandbox.org
Another alternative: provide an overload of foo that takes a reference:
void foo(Key&& key)
{
foo(&key);
}
Just control the scope of the throw-away variable yourself:
{
Key key;
foo(&key);
} // <-- 'key' is destroyed here
This is a utilty function. It is basically the inverse of std::move1:
template<class T>
T& as_lvalue( T&& t ) { return t; }
if used wrong it can lead to dangling references.
Your code then becomes:
foo(&as_lvalue(Key()));
the goal of "cannot take an address of a temporary" is because you can otherwise get extremely unexpected behaviour due to things like implicit temporary creation.
In this case, we are explicitly taking the address of a temporary.
It is no more dangerous than creating a named value, calling the function, and then discarding the named value immediately.
1 std::move takes an l or r value and returns a rvalue reference to it, indicating that consumer should treat it as a temporary whose existence will be shortly discarded. as_lvalue takes an l or r value reference and returns an lvalue reference to it, indicating that the consumer should treat it as a non-temporary whose existence will persist.
They are both valid operations, but std::move is more crucial. (std::move could be called as_rvalue really). I'd advise against clever names like unmove.
The only reason to take a pointer rather than a reference is if the pointer can be null. And if that's the case, then your foo function will look something like this:
void foo(const Key *key)
{
if(key)
//Do stuff with `key`
else
//Alternate code
}
Given that, what you want is a second overload, one that refactors all of the "do stuff with key" into its own function that takes a reference. So do that:
void foo(const Key &key)
{
//Do stuff with `key`
}
void foo(const Key *key)
{
if(key)
foo(*key);
else
//Alternate code.
}
If you have common code that gets executed in both cases, refactor that out into its own function too.
Yes, it's possible that "do stuff with key" is complicated and is split up into several lines. But that suggests a very strange design here.
You could also refactor it the other way:
void foo(const Key &key) {foo(&key);}
I use something like this:
template <typename T>
const T* temp_ptr(const T&& x) { return &x; }
Used like this:
foo(temp_ptr(Key{}));
This is very useful when dealing with certain legacy APIs. DirectX 11 in particular frequently takes parameter aggregating structs by const T* and it's convenient to create and pass them inline. I don't think there's anything wrong with this idiom unlike some of the commenters here, although I'd prefer if those APIs just took a const reference and handled optional arguments differently.
Here's an example D3D11 API call where this is very useful:
vector<Vec3f> verts;
...
ID3D11BufferPtr vbuf;
d3dDevice->CreateBuffer(
temp_ptr(CD3D11_BUFFER_DESC{byteSize(verts), D3D11_BIND_VERTEX_BUFFER}),
temp_ptr(D3D11_SUBRESOURCE_DATA{data(verts)}), &vbuf);
For calling ID3D11Device::CreateBuffer() to create a vertex buffer.
On larger projects I might write wrappers for many of the D3D API calls which make them more convenient to call in a modern C++ style but for small standalone sample projects that I want to have minimum extra code or dependencies I find this very useful.
Another trick I've used in the past that works is:
foo(std::data({Key{}}));
But I don't particularly recommend this as I think the intent is unclear and relies on a bit too much knowledge of how initializer lists work. A variation is useful if you need to pass a temporary 'array' though:
d3dDeviceContext->ClearRenderTargetView(rendertarget, data({0.0f, 0.0f, 0.0f, 0.0f}));
For calling an API like ID3D11DeviceContext::ClearRenderTargetView().
if what you concern is variable scope (as you mention in comment) you can use
{Key key;foo(&key);}
Or I could do:
foo(new Key());
But then the object will not be deleted.
You could create a smart pointer, but I'd rather not. It still is a possibility though.
#include <memory>
foo(std::make_unique<const Key>().get());
I have in my project a couple of functions that create objects. For example, if you have a function that makes an object like this:
int& f()
{
int *i = new int(5);
return *i;
}
and then when you call that you do
int x = f();
or something like
std::cout << f();
what happens to the int that was created in the function? Is the reference handled like a normal variable or am I doing something terribly wrong? And if so, what is the correct way to make objects?
This is terribly wrong, indeed. The moment you forget about your reference is the moment you'll leak a resource. And you're doing just that with int x = f();.
Same with the second case, std::cout << f(); - don't use this at all if you aren't going to delete that dynamically allocated int.
int is also passed to std::basic_ostream::operator<< by value, a copy is made. This doesn't actually matter, no normal code would accept a reference and then call delete &ref;.
Here's a link for you: RAII.
I can't know what you want from your contrived example, but consider returning by value, or using smart pointers in case of polymorphism.
if you want to show that function delegates ownership of the created object with new you have to do it explicitly for example with std::unique_ptr. As you can see your function becomes self documented and you need not look into the body to understand who response for deleting:
std::unique_ptr<int> foo() {
return std::make_unique<int>(5);
}
I'm actually working on pointers to user-defined objects but for simplicity, I'll demonstrate the situation with integers.
int* f(){
return new int(5);
}
void f2(int* i){
*i = 10;
}
int main(){
int* a;
int* b = new int();
a = f();
f2(b);
std::cout << *a << std::endl; // 5
std::cout << *b << std::endl; // 10
delete b;
delete a;
return 0;
}
Consider that in functions f() and f2() there are some more complex calculations that determine the value of the pointer to be returned(f()) or updated through paramteres(f2()).
Since both of them work, I wonder if there is a reason to choose one over the other?
From looking at the toy code, my first thought is just to put the f/f2 code into the actual object's constructor and do away with the free functions entirely. But assuming that isn't an option, it's mostly a matter of style/preference. Here are a few considerations:
The first is easier to read (in my opinion) because it's obvious that the pointer is an output value. When you pass a (nonconst) pointer as a parameter, it's hard to tell at a glance whether it's input, output or both.
Another reason to prefer the first is if you subscribe to the school of thought that says objects should be made immutable whenever possible in order to simplify reasoning about the code and to preclude thread safety problems. If you're attempting that, then the only real choice is for f() to create the object, configure it, and return const Foo* (again, assuming you can't just move the code to the constructor).
A reason to prefer the second is that it allows you to configure objects that were created elsewhere, and the objects can be either dynamic or automatic. Though this can actually be a point against this approach depending on context--sometimes it's best to know that objects of a certain type will always be created and initialized in one spot.
If the allocation function f() does the same thing as new, then just call new. You can do whatever initialisation in the object's construction.
As a general rule, try to avoid passing around raw pointers, if possible. However that may not be possible if the object must outlive the function that creates it.
For a simple case, like you have shown, you might do something like this.
void DoStuff(MyObj &obj)
{
// whatever
}
int Func()
{
MyObj o(someVal);
DoStuff(o);
// etc
}
f2 is better only because the ownership of the int is crystal clear, and because you can allocate it however you want. That's reason enough to pick it.
My colleague recently compiled our program in Windows, and discovered a bug of the sort:
std::string a = "hello ";
std::string b = "world";
const char *p = (a+b).c_str();
printf("%s\n", p);
which for some reason did not crash in our Linux executables.
None of our compilers give any kind of warning, so we are now worried that this error might exist in the code.
Although we can grep for c_str() occurrences and do a visual inspection, there is a possibility that one might have also done the following:
struct I {
int num;
I() { num=0; }
};
struct X {
I *m;
X() { m = new I; }
~X() { delete m; }
I get() { return *m; } // version 1, or
I& get() { return *m; } // version 2
};
and accessed it like:
I& a = X().get(); // will get a reference to a temporary, or a valid copy?
cout << a.num;
instead of :
cout << X().get().num;
which is safe (isn't it?)
Question: Is there a way I can catch such errors (perhaps using the compiler, or even an assertion) ?
I need to be sure that if author of struct X changes get() between version 1 and 2 that the program will warn for the error
Simple answer: In general you cannot catch those errors, and the reason is that there are similar constructs that might be perfectly fine, so the compiler would have to know the semantics of all the functions to be able to warn you.
In simpler cases, like obtaining the address of a temporary, many compilers already warn you, but in the general case, it is quite difficult if not impossible for the compiler to know.
For some similar example to the .c_str() consider:
std::vector< const char * > v;
v.push_back( "Hi" );
const char* p = *v.begin();
The call to begin returns a temporary, similar to the expression (a+b), and you are calling a member function of that temporary (operator*) that returns a const char*, which is quite similar to your original case (from the point of view of the types involved). The problem is that in this case the pointee is still valid after the call, while in yours (.c_str()) it isn't, but it is part of the semantics of the operation, not the syntax that the compiler can check for you. The same goes for the .get() example, the compiler does not know if the returned reference is to an object that will be valid after the expression or not.
All these fall under the category of Undefined Behavior.
Check out this question's solution, I think it does something similar to what you're looking for:
C++ catching dangling reference
There are runtime based solutions which instrument the code to check
invalid pointer accesses. I've only used mudflap so far (which is
integrated in GCC since version 4.0). mudflap tries to track each
pointer (and reference) in the code and checks each access if the
pointer/reference actually points to an alive object of its base type.
Here is an example: {...}