Given the following test code
#include <iostream>
#include <tr1/functional>
using namespace std;
struct cl {
cl(){ cout << " cl()\n"; }
cl(const cl& from){ cout << " cl()[copy]\n"; }
~cl(){ cout << " ~cl()\n";}
};
void f1(const cl& data){}
void f2(const cl* pData){}
int main(int c, char** a)
{
cout << "enter:\n";
cl data;
cout << "ref:\n";
tr1::bind(&f1, data);
cout << "ptr:\n";
tr1::bind(&f2, &data);
cout << "exit:\n";
return 0;
}
I get the following output:
$ g++ tr1BindDtorTest.cpp && ./a.out
enter:
cl()
ref:
cl()[copy]
cl()[copy]
cl()[copy]
~cl()
~cl()
~cl()
ptr:
exit:
~cl()
When I create a binding involving references to my class/struct objects are created and destroyed multiple times.
Same exact test but with pointers there are no such objects
I can't see why the behaviour will be different between pass by value & reference, I always thought of reference as syntactic sugar for pointer, and so reasoned that the behaviours should be identical.
Anyone care to explain?
[g++ 4.4.6 linux & 4.2.1 on macos]
Instead of this:
tr1::bind(&f1, data);
You need this:
tr1::bind(&f1, tr1::ref(data));
Boost has the same thing: boost::ref() must be used inside boost::bind() if you want the bound function object to store a reference to the data. Otherwise, the data will always be copied into the bound function object produced by bind().
See cppreference documentation:
The arguments to bind are copied or moved, and are never passed by
reference unless wrapped in std::ref or std::cref.
Related
We are creating a class designed to send information out from the current module (the specifics are not relevant to this question). An object of this type is created and populated with a portion of the data that needs to be sent, and then passed into a (different class) member function. That function provides the object with the rest of the data, and then triggers the send, via a call in the object itself. Because the information being passed in is dynamic, the intention is that the information transfer object be a temporary one, created with the latest data. The design we lined out is in the distilled source code below, but gcc/C++ does not allow this, giving the error shown.
The question is, how can we accomplish the intended behavior, using temporary objects (nice for avoiding memory leaks) that can be modified and used by the called function?
gcc compiler error:
infoxfer.cpp: In function ‘int main()’:
infoxfer.cpp:54:43: error: cannot bind non-const lvalue reference of type ‘XferInfo&’ to an rvalue of type ‘XferInfo’
51 | callee.doSomething("Something param", XferInfo("from main()"));
| ^~~~~~~~~~~~~~~~~~~~~~~
infoxfer.cpp:36:62: note: initializing argument 2 of ‘void Callee::doSomething(const string&, XferInfo&)’
33 | void doSomething(const string& somethingParam, XferInfo& xferInfo)
| ~~~~~~~~~~^~~~~~~~
The distilled sample code:
infoxfer.cpp:
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
class XferInfo
{
private:
const string mCallerInfo;
string mCalleeInfo;
public:
XferInfo(const string& callerInfo) : mCallerInfo(callerInfo)
{}
void setCalleeInfo(const string& calleeInfo)
{
mCalleeInfo = calleeInfo;
}
void sendData()
{
// simulate sending data
cout << mCallerInfo << " | " << mCalleeInfo << endl;
}
};
class Callee
{
public:
void doSomething(const string& somethingParam, XferInfo& xferInfo)
{
// complete data for xfer
xferInfo.setCalleeInfo(somethingParam);
// simulate doing something
cout << "do something" << endl;
// send the complete info
xferInfo.sendData();
}
};
int main()
{
cout << "start" << endl;
Callee callee;
callee.doSomething("Something param", XferInfo("from main()"));
cout << "end" << endl;
return 0;
}
As mentioned in the comments, you could simply change your doSomething function to accept an rvalue reference to the passed XferInfo object (using the double &&):
void doSomething(const string& somethingParam, XferInfo&& xferInfo)
{
// complete data for xfer
xferInfo.setCalleeInfo(somethingParam);
// ... and so forth ...
From the linked cppreference page:
Rvalue references can be used to extend the lifetimes of temporary
objects (note, lvalue references to const can extend the lifetimes of
temporary objects too, but they are not modifiable through them)
I just started learning the new C++ memory model:
#include <string>
#include <iostream>
#include <memory>
void print(unique_ptr<std::string> s) {
std::cout << *s << " " << s->size() << "\n";
}
int main() {
auto s = std::make_unique<std::string>("Hello");
print(std::move(s));
std::cout << *s;
return 0;
}
Right now calling cout << *s; results in a segfault, as it should. I understand why it happens. But I also would like to know if there's a way get back the ownership. I'd like to be able to use a value after passing it to a function.
If you don't want to transfer ownership of the owned object, then don't pass the unique_ptr to the function. Instead, pass a reference or a raw pointer to the function (in modern C++ style, a raw pointer is usually understood to be non-owning). In the case where you just want to read the object, a const reference is usually appropriate:
void print(const std::string&);
// ...
print(*s);
I was revisiting the concepts of structures in C++ before the lectures and written the following:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct isOdd{
bool operator()(int x){
return x%2;
}
};
int main(){
vector<int> v {3,4,2,1,65,2,4,65,2,9,8,5,7};
int count = count_if(begin(v), end(v), isOdd());
cout << "size of vector: " <<v.size() << endl;
cout << "count of odds: " <<count << endl;
return 0;
}
Then I realize that in calling function of structure isOdd, I have used the syntax: isOdd() but I have only overridden the () operator. So how the calling convention isOdd() is working because the calling a function of structure is like:
structure::function-name();
or structure-object.functions-name();
Can somebody elaborate the doubt?
Thanks.
Then I realize that in calling function of structure isOdd, I have
used the syntax: isOdd() but I have only overridden the () operator.
No, You called the implicit compiler generated default constructor, thereby creating a temporary object of isOdd.
For example: If you wanted to test it on a single number without creating a named isOdd object, you could:
bool is_odd = isOdd()(4);
//^^ Creates a temporary object
Optimizing Compilers will elide the creation of the temporary object since it neither has observable side effects nor a state.
I'm testing my understanding of lvalue and rvalue references by intentionally trying to break things. So say there is this struct:
struct FooBar
{
FooBar(int&& number) : rNumber(number)
{
}
int& rNumber;
};
and I create an instance FooBar obj(5). Every attempt to read the reference variable returns the right result (5). The same happens if I use const int& instead of int&&.
I noticed that replacing int with std::string and reading the reference returns an empty string, so I suspect it gives undefined behaviour. Is this so? And if so, why does it work with integers?
Update: I'm creating the instance and reading it like this:
FooBar obj(5);
//FooBar obj("Hello"); // For strings...
std::cout << obj.rNumber << std::endl;
Update 2: It also works if you pass a user-defined type, like this:
struct GooBar
{
public:
GooBar(int number) : itsNumber(number)
{
std::cout << "In constructor..." << std::endl;
}
GooBar(const GooBar& rhs) = delete;
GooBar(GooBar&& rhs) = delete;
~GooBar()
{
std::cout << "In destructor..." << std::endl;
}
int itsNumber;
};
struct FooBar
{
FooBar(GooBar&& number) : rNumber(number)
{
}
GooBar& rNumber;
};
and then creating an instance and reading it like so:
FooBar obj(GooBar(5));
std::cout << obj.rNumber.itsNumber << std::endl;
I think this is interesting, because it gives the following output:
In constructor...
In destructor...
5
With an integer literal as actual argument the compiler may pass a reference to a statically allocated instance.
With a std::string formal argument and a string literal as actual argument, the instance is created in the call, and is destroyed at the end of the call.
In both cases it's Undefined Behavior.
It's not clear how you call this though: you forgot to include that crucial information (as the question is as at time I'm writing this).
Can someone tell why test(2) object is destroyed after test_method() call?
#include<iostream>
#include<string>
using namespace std;
class test
{
int n;
public:
test(int n) : n(n)
{
cout << "test: " << n << endl;
}
~test()
{
cout << "~test: " << n << endl;
}
test & test_method()
{
cout << "test_method: " << n << endl;
return *this;
}
};
int main(int argc, const char *argv[])
{
cout << "main start" << endl;
const test &test1 = test(1);
const test &test2 = test(2).test_method();
cout << "main end" << endl;
}
Output is:
main start
test: 1
test: 2
test_method: 2
~test: 2
main end
~test: 1
test(2).test_method() returns a reference, which is bound to test2, and then the object to which it refers is destroyed at the end of the full expression, since it is a temporary object. That should not be a surprise.
The real surprise is that test1 remains a valid reference, because it is directly bound to a temporary, and binding a temporary to a reference extends the lifetime of the temporary to that of the reference variable.
You only have to note that in the test(2) case, the temporary object isn't bound to anything. It's just used to invoke some member function, and then its job is done. It doesn't "babysit" member functions, or in other words, lifetime extension isn't transitive through all possible future references.
Here's a simple thought experiment why it would be impossible to actually have "arbitrary lifetime extension":
extern T & get_ref(T &);
{
T const & x = get_ref(T());
// stuff
// Is x still valid?
}
We have no idea if x remains valid beyond the first line. get_ref could be doing anything. If it's implemented as T & get_ref(T & x) { return x; }, we might hope for magic, but it could also be this:
namespace { T global; }
T & get_ref(T & unused) { return global; }
It's impossible to decide within the original translation unit whether anything needs to be extended or not. So the way the standard has it at present is that it's an entirely trivial, local decision, just made when looking at the reference declaration expression, what the lifetime of the temporary object in question should be.
Because the C++ standard requires this behavior. Give the object a name if you want it to persist. It will persist as long as the name.
Edit: You your example, test1 is the name that you gave to the first object, whereas the second object has obtained no name at all, and so it does not outlast evaluation of the expression.