I'm using an async function that takes an object reference &foo and a callback cb as arguments. I want to prevent destruction of foo until the callback is called.
void async_thing(Foo &foo, function<void()> cb) {
// do something asynchronously with foo
}
Is it enough to simply capture it in the callback lambda? Or does it need to be actually used in the lambda?
auto foo = make_shared<Foo>();
async_thing(*foo, [foo]() {
cout << "Callback ran" << endl;
});
Might a compiler optimise the capture out, and delete foo prematurely?
n3690, section 5.1.2
15.
An entity is captured by copy if it is implicitly captured and the
capture-default is = or if it is explicitly captured with a capture
that does not include an &. For each entity captured by copy, an
unnamed nonstatic data member is declared in the closure type.
Above which we have:
3.
The type of the lambda-expression (which is also the type of the
closure object) is a unique, unnamed nonunion class type — called the
closure type.
[…]
An implementation may define the closure type
differently from what is described below provided this does not alter
the observable behavior of the program other than by changing:
the size and/or alignment of the closure type,
whether the closure type is trivially copyable (Clause 9),
whether the closure type is a standard-layout class (Clause 9), or
whether the closure type is a POD class (Clause 9).
From this I would conclude that:
The capture makes a shared_ptr member in the closure type.
The compiler is not allowed to alter that observable behavior.
So your pointer won't be deleted until the destructor of the closure is called.
Related
Here is the code:
class SomeType {
public:
SomeType() {}
~SomeType() {}
std::string xxx;
}
bool funtion_ab() {
SomeType(); // This is a right val;
// The right val destructs here when I test the code. I want to make sure that it would always destructs here.
int a = 0, b = 10;
....// other code
return true;
}
Please tell me if you know the truth. Thank you!
What you have is called a temporary object. From §6.7.7,
Temporary objects are created
when a prvalue is converted to an xvalue
or, more specifically,
[Note 3: Temporary objects are materialized:
...
when a prvalue that has type other than cv void appears as a discarded-value expression ([expr.context]).
— end note]
and, on the lifetime, the same section has this to say
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
You can read more about the expression semantics, but in your case "full-expression" is fairly unambiguous.
SomeType();
The "full-expression" containing your constructor call is... the constructor call itself. So the destructor will be called immediately after evaluating the constructor. There are some exceptions to this rule (such as if the temporary object is thrown as an exception or is bound as a reference), but none of those apply here.
As noted in the comments, compilers are free to inline your constructor and destructor calls and then are free to notice that they do nothing and omit them entirely. Optimizers can do fun stuff with your code, provided it doesn't change the semantics. But a strict reading of the standard states that the destructor is called exactly where you suggested.
I'm trying to understand the Wire library in Golang and find that in the wire.go there's a function looks like this:
func NewSet(...interface{}) ProviderSet {
return ProviderSet{}
}
It looks foreign to me as to why the ...interface{}) parameter is unnamed (meaning not being used inside the function) but then the caller still passes meaningful values to it?
var Set = wire.NewSet(
wire.Value(Foo(41)),
provideFooBar)
Parameters being named or unnamed has nothing to do with whether the caller having to pass values for them. Being unnamed just means they cannot be used (cannot be referred to) inside the function.
NewSet has a variadic parameter, which means any number of arguments may be passed to it that can be assigned to the type, and any value can be assigned to interface{} (all value implements the empty interface).
The "empty" implementation of NewSet() you see is just a placeholder for documentation and compilers. The generated code will use the passed arguments.
If you have a function:
func dummy(int) {}
You can't call it like dummy(), that's a compile-time error. You can only call it by passing an int value to it, e.g. dummy(1).
See related: Is unnamed arguments a thing in Go?
In this sample:
auto f = [](int some, int some2){
//do something
};
This case it is a functor or object of function?
std::function<void(int, int)> f = [](int some, int some2) {
//do something
}
Now, in this case, whats is the results? Functor or Object of function?
The first f (i.e., the one designated with auto) results to what is called a lambda function. Also knows as a closure. Closures are unnamed function objects. That's why we need auto to deduce the type of a closure. We don't know it's type but the compiler does. Thus, by using auto we let the compiler deduce the type of the unnamed closure object for us.
The second f (i.e., the one designated with std::function) is a std::function object. Class std::function is a general-purpose polymorphic function wrapper.
Lambdas closures as function objects can be converted to their respective std::function objects. That is exactly what is happening in:
std::function<void(int, int)> f = [](int some, int some2) {
//do something
}
The lambda closure on the right hand side is assigned and converted to the std::function object on the left side of the assignment.
Practically, they're both interpreted as functors, since they both overload call operator() and thus can be called, except for that the lambda's type is unnamed.
Another difference between those two is that you can't assign between lambda closures, since for lambda closures the assignment operator is declared deleted. while you can assign between std::function objects.
It is my understanding that move semantics can use move-constructors to elide what would otherwise be a copy. For example, a function returning a (perhaps) large data structure can now return by value, and the move constructor will be used to avoid a copy.
My question is this: is the compiler required to not copy when this is possible? It doesn't seem to be the case. In that case, wouldn't the following code have "implementation-defined" semantics?
static const int INVALID_HANDLE = 0xFFFFFFFF;
class HandleHolder {
int m_handle;
public:
explicit HandleHolder(int handle) : m_handle(handle) {}
HandleHolder(HandleHolder& hh) {
m_handle = hh.m_handle;
}
HandleHolder(HandleHolder&& hh) : m_handle(INVALID_HANDLE) {
swap(m_handle, hh.m_handle);
}
~HandleHolder() noexcept {
if (m_handle != INVALID_HANDLE) {
destroy_the_handle_object(m_handle);
}
}
};
Say then we make a function:
HandleHolder make_hh(int handle) { return HandleHolder(handle); }
Which constructor is called? I would expect the move constructor, but am I guaranteed the move constructor?
I'm aware this is a silly example and that -- for example -- the copy constructor of this object should be deleted because there is no way to use it safely otherwise, but the semantics are simple enough that I wouldn't think something like this would be implementation-defined.
Yes, of course. There's nothing implementation-defined about it.
If there is a move constructor and it can be used, and it is a choice between a move constructor and a copy constructor, the move constructor will be invoked. That is a guarantee.
[C++11: 13.3.3.2/3]: [..] Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if:
[..]
S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
[..]
I think your confusion stems from misuse of the term "elide". The compiler may elide copies/moves and replace them with nothingness — with in-place construction that bypasses the invocation of a constructor altogether. Copy elision never results in a move, and move elision never results in a copy. Either the object "transferral" happens or it does not.
You could sort of argue that your program has "implementation-defined" semantics in the sense that you don't know whether copies/moves will be elided until the program has been compiled, and because such elision is allowed to modify side-effects (such as console output). But we don't tend to think of it that way.
Regardless, this does not affect which of the copy and move constructors will be invoked if either are to be.
Your example is further flawed because only your move constructor can be invoked: your copy constructor takes a ref-to-non-const which can't be bound through an rvalue initialiser.
A particular property of c++'s lambda expressions is to capture the variables in the scope in which they are declared. For example I can use a declared and initialized variable c in a lambda function even if 'c' is not sent as an argument, but it's captured by '[ ]':
#include<iostream>
int main ()
{int c=5; [c](int d){std::cout<<c+d<<'\n';}(5);}
The expected output is thus 10. The problem arises when at least 2 variables, one captured and the other sent as an argument, have the same name:
#include<iostream>
int main ()
{int c=5; [c](int c){std::cout<<c<<'\n';}(3);}
I think that the 2011 standard for c++ says that the captured variable has the precedence on the arguments of the lambda expression in case of coincidence of names. In fact compiling the code using GCC 4.8.1 on Linux the output I get is the expected one, 5. If I compile the same code using apple's version of clang compiler (clang-503.0.40, the one which comes with Xcode 5.1.1 on Mac OS X 10.9.4) I get the other answer, 3.
I'm trying to figure why this happens; is it just an apple's compiler bug (if the standard for the language really says that the captured 'c' has the precedence) or something similar? Can this issue be fixed?
EDIT
My teacher sent an email to GCC help desk, and they answered that it's clearly a bug of GCC compiler and to report it to Bugzilla. So Clang's behavior is the correct one!
From my understanding of the c++11 standard's points below:
5.1.2 Lambda expressions
3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called
the closure type — whose properties are described below.
...
5 The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are
described by the lambda-expression’s parameter-declaration-clause and
trailing-return-type respectively. This function call operator is
declared const (9.3.1) if and only if the lambda-expression’s
parameter-declaration-clause is not followed by mutable.
...
14 For each entity captured by copy, an unnamed non static data member is declared in the closure type
A lambda expression like this...
int c = 5;
[c](int c){ std::cout << c << '\n'; }
...is roughly equivalent to a class/struct like this:
struct lambda
{
int c; // captured c
void operator()(int c) const
{
std::cout << c << '\n';
}
};
So I would expect the parameter to hide the captured member.
EDIT:
In point 14 from the standard (quoted above) it would seem the data member created from the captured variable is * unnamed *. The mechanism by which is it referenced appears to be independent of the normal identifier lookups:
17 Every id-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.
It is unclear from my reading of the standard if this transformation should take precedence over parameter symbol lookup.
So perhaps this should be marked as UB (undefined behaviour)?
From the C++11 Standard, 5.1.2 "Lambda expressions" [expr.prim.lambda] #7:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator,
but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions
referring to non-static class members into class member access expressions using (*this) (9.3.1),
the compound-statement is considered in the context of the lambda-expression.
Also, from 3.3.3 "Block scope" [basic.scope.local] #2:
The potential scope of a function parameter name (including one appearing in a lambda-declarator) or of
a function-local predefined variable in a function definition (8.4) begins at its point of declaration.
Names in a capture list are not declarations and therefore do not affect name lookup. The capture list just allows you to use the local variables; it does not introduce their names into the lambda's scope. Example:
int i, j;
int main()
{
int i = 0;
[](){ i; }; // Error: Odr-uses non-static local variable without capturing it
[](){ j; }; // OK
}
So, since the parameters to a lambda are in an inner block scope, and since name lookup is done in the context of the lambda expression (not, say, the generated class), the parameter names indeed hide the variable names in the enclosing function.