I am struggling to turn this piece of code into a one-liner:
std::string filename = "cats";
std::shared_ptr<bmd2::Bmd2Dataset> ptr (new bmd2::Bmd2Dataset(filename, bmd2::File::FM_WRITE));
bmd2::bmd2Session::getInstance().addDataset(ptr);
The above works great -- but can I call addDataset without creating the lvalues (lines 1 + 2)?
Here is the declaration of addDataset():
int addDataset(std::shared_ptr<bmd2::Bmd2Dataset> &) throw (bmd2Exception);
bmd2::bmd2Session::getInstance().addDataset(
std::make_shared<bmd2::Bmd2Dataset>("cats", bmd2::File::FM_WRITE)
);
One statementer. :)
Interesting. For learning purposes, can you tell me if you can accomplish this without the make_shared() function call?
You can, using C++11's brace initialization syntax. Assuming addDataset isn't a template and has std::shared_ptr<bmd2::Bmd2Dataset> as its parameter,
bmd2::bmd2Session::getInstance().addDataset(
{ new bmd2::Bmd2Dataset("cats", bmd2::File::FM_WRITE) }
);
UPDATE: Oops. So addDataset() actually accepts an l-value reference why didn't you say so immediately?. addDataset()'s parameter can't bind to r-value parameters, which in the two above examples are. To solve this, you can either:
Make addDataset()'s parameter a const reference
int addDataset(const std::shared_ptr<bmd2::Bmd2Dataset> &) throw (bmd2Exception);
// ^^^^^
Do this if you don't need to modify the passed shared_ptr argument (i.e. modifying it so it points to another object).
Use your older method, though passing directly "cat" into the the new expression. UPDATE: Use std::make_shared!
auto ptr = std::make_shared<bmd2::Bmd2Dataset>("cats", bmd2::File::FM_WRITE);
bmd2::bmd2Session::getInstance().addDataset(ptr);
// ptr might now point to some other object
Do this if you want the passed argument's (ptr) value to be changed (i.e. after the call it might now point to a new object).
Related
A short yet effective example below:
std::unique_ptr<float> x(new float[whatever_size]);
I have a function with prototype:
void function(float*&);
How can I go about calling it by passing in the x.
I tried:
function(x.get()); // complains no argument matches float*&
function(&x.get()); // complains requires lvalue.
A short answer with an explanation would be great.
Thanks!
To start with, you should know that a unique pointer doesn't magically protect you from messing up memory management. Your use case is extremely fishy, and I would caution you to not assume a unique pointer will solve everything and anything.
function expects a modifiable lvalue reference. The call x.get() returns an rvalue. Naturally the reference won't bind to it, no matter how hard you try. Now, the obvious solution is to introduce a temporary:
auto *f = x.get();
function(f);
But that may come back and shoot you in the foot if function needs to actually modify f, the pointer and not the pointee.
Since you mentioned it a comment that it indeed modifies its argument. You must reliniquish ownership from the unique pointer before the call, and give it back after:
auto *f = x.release();
function(f);
x.reset(f);
That is the only way the change will reflect in x. But again, it's still a bit fragile.
The problem here is that the function can modify the pointer you pass to it (passed by non-const reference), potentially re-seating it. If that is the case, then you would have to do something like this:
std::unique_ptr<float[]> x(new float[N]); // remember the array type []
float* fp = x.release();
func(fp);
x.reset(fp);
But the critical point is passing in a proper (named) pointer, not just a temporary pointer returned by x.get().
Your error occurs because the function is unable to modify the temporary pointer returned by the function x.get(). You have to give it a real pointer that can change value.
I have some Qt code that I downloaded from my svn repo. It's a while since I worked on it but I am sure it used to compile.
I have a new version of Qt and compiler (to what I had in the last time). My current compiler is: mingw 4.9.2 32-bit.
So here is my problem code:
QByteArray dataBlock = audioTestFile.read(PACKET_SIZE_TO_ENCODE);
// This line is the issue
uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()));
Where:
typedef std::vector<uint8_t> uint8Vect_t;
and
uint8Vect_t encodeData(uint8Vect_t &dataBuff);
So you can see here that I have a function encodeData() which takes a parameter uint8Vect_t & (pass by ref). I am passing a temporary variable (an rvalue I think) created using the std::vector constructor (one of which takes two iterators) from the QByteArray dataBlock iterators (which I have tested works).
However, I get the error:
../audioTest/txaudiostream.cpp: In member function 'void
CTxAudioStream::playFile()': ../audioTest/txaudiostream.cpp:212:94:
error: no matching function for call to
'CTxAudioStream::encodeData(uint8Vect_t)'
uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()));
^ ../audioTest/txaudiostream.cpp:212:94: note: candidate is:
../audioTest/txaudiostream.cpp:36:13: note: uint8Vect_t
CTxAudioStream::encodeData(uint8Vect_t&) uint8Vect_t
CTxAudioStream::encodeData(uint8Vect_t &dataBuff)
^ ../audioTest/txaudiostream.cpp:36:13: note: no known conversion for argument 1 from 'uint8Vect_t {aka std::vector}' to 'uint8Vect_t& {aka std::vector&}'
Basically it's saying that I cannot convert from uint8Vect_t to uint8Vect_t&. But if I pass a variable of type uint8Vect_t into the function (rather then the return value of the contructor / temp variable) then this works ok.
I thought in c++11 you can pass rvalues.. but I am obviously missing something here. Can anyone explain:
Why this is wrong?
What is an efficient/elegant (readable) solution?
Your issue is
uint8Vect_t encodeData(uint8Vect_t &dataBuff);
Here you are taking a reference to a uint8Vect_t. That works well with normal variables but uint8Vect_t(dataBlock.begin(), dataBlock.end()) is a temporary object and cannot be bound to lvalue reference.
If encodeData() does not change dataBuff then the simplest solution is to take a const & which can bind to a temproary.
uint8Vect_t encodeData(const uint8Vect_t &dataBuff);
If you have to change the contents of dataBuff then you would have to write another version of encodeData() that takes an rvalue reference
uint8Vect_t encodeData(uint8Vect_t &&dataBuff);
This will allow the function to bind to the temporary vector and you can work on it in the function as you would a normal vector.
I believe the reason you are seeing this is that your old compiler was a version of Microsoft Visual Studio. MSVS has a non standard extension that is on by default that allows temporary objects to bind to a lvalue reference. You can read more about it at: Non-const reference bound to temporary, Visual Studio bug?
Adding this to show you how you could change encodeData() to take an rvalue reference without having to write a new function.
#include <iostream>
#include <vector>
std::vector<int> modify(std::vector<int>& foo)
{
for (auto & e : foo)
e *= 2;
return foo;
}
std::vector<int> modify(std::vector<int>&& foo)
{
return modify(foo);
}
int main()
{
std::vector<int> foo = modify({ 1,2,3,4,5 });
for (const auto & e : foo)
std::cout << e << " ";
}
Live Example
In the above example modify({ 1,2,3,4,5 }) calls modify(std::vector<int>&& foo) and then in the function foo is an lvaue. We then return the result of passing the "new" lvalue to modify(std::vector<int>& foo) which then returns a modified vector.
When you use
encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()))
the vector you pass into the function is a temporary object, and references can't bind to temporary objects.
The simple solution, if the function doesn't modify the argument, is to make it a reference to a constant object:
uint8Vect_t encodeData(uint8Vect_t const& dataBuff);
References to constant objects can bind to temporary objects.
What do you want to do with/to the object you are passing in?
When you take it as uint8Vect_t &dataBuff that should mean you want to make lasting modifications to it, which makes no sense if it is a temporary.
When you take it as uint8Vect_t const&dataBuff that should mean you want to copy from it and not modify it, which is probably what you want.
When you take it as uint8Vect_t dataBuff that should mean you need your own local temporary copy of it, to use as you wish and then throw away, and that should be important enough to be worth the cost of copying.
When you take it as uint8Vect_t &&dataBuff that should mean you want to make non lasting modifications (such as content stealing) from a temporary object that the caller is effectively promising to throw away after you are done with it.
That last choice is the one new in C++11 for passing rvalues.
Return value of any function is an temporary object(rvalue) and you can't pass temporary object as reference.
below code will generate same error as we are trying to pass "saurabh"(temp object) as reference type.
i.e.
void fun(string& name){
//statements;
}
int main(){
fun("Saurabh");
return 0;
}
std::shared_ptr::operator* returns by lvalue reference, and the answer given on overloading pointer like operations here says that the convention is to return by lvalue reference. However, when I'm using the following code, I get error C2664: 'AdjacencyList::addVertex' : cannot convert parameter 1 from 'AdjacencyList::vertex_type' to 'AdjacencyList::vertex_type &&': You cannot bind an lvalue to an rvalue reference:
std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type&& v)
{
auto existingVertex(findVertex(v));
if (!existingVertex.isValid())
{
existingVertex = std::make_shared<vertex_type>(std::forward<vertex_type>(v))
m_vertices.push_back(existingVertex);
}
return existingVertex;
};
AdjacencyList minimumSpanningTree;
// startVertex is a shared_ptr to a vertex returned from a previous call of addVertex
// on another AdjacencyList object
const auto mstStartVertex(minimumSpanningTree.addVertex(*startVertex));
Should I provide AdjacencyList::addVertex(const vertex_type& v) or change the code at the bottom of the above block to make a copy of the vertex before passing to addVertex?
AdjacencyList minimumSpanningTree;
Vertex s(*startVertex);
const auto mstStartVertex(minimumSpanningTree.addVertex(std::move(s)));
I would think that you should return a copy from your operator*, as the sematics of the std::weak_ptr suggest that you can not guarantee that a returned reference would stay valid. Since the returned copy is then given to a function which can move it somewhere else, it should also be efficient enough, since addVertex looks like it would require a copy anyways, i.e., if you would create an overload of addVertex, it will create a copy of the passed const reference internally, would it?
The most efficient approach in terms of redundant copies is to provide rvalue and const reference overloads:
std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type&&);
std::shared_ptr<vertex_type> AdjacencyList::addVertex(const vertex_type&);
To eliminate the redundant code, you can forward to a template method or to a concrete method taking a bool flag and performing const_cast as appropriate.
If the overhead of copying the Vertex object is minimal compared to the cost of increased code, and if the if block is usually or often entered, then the redundant copy will make your code clearer. Your second suggested call will work better if you just create a prvalue temporary that doesn't need to be moved:
const auto mstStartVertex(minimumSpanningTree.addVertex(Vertex{*startVertex}));
However in that case you might as well create the temporary in the call itself, by providing a single value overload (How to reduce redundant code when adding new c++0x rvalue reference operator overloads):
std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type);
I'm currently reading through Accelerated C++ and I realized I don't really understand how & works in function signatures.
int* ptr=#
means that ptr now holds the address to num, but what does that mean?
void DoSomething(string& str)
from what I understand that is a pass by reference of a variable (which means passing the address) but when I do
void DoSomething(string& str)
{
string copy=str;
}
what it creates is a copy of str. What I thought it would do is raise an error since I'm trying to assign a pointer to a variable.
What is happening here? And what is the meaning of using * and & in function calls?
A reference is not a pointer, they're different although they serve similar purpose.
You can think of a reference as an alias to another variable, i.e. the second variable having the same address. It doesn't contain address itself, it just references the same portion of memory as the variable it's initialized from.
So
string s = "Hello, wordl";
string* p = &s; // Here you get an address of s
string& r = s; // Here, r is a reference to s
s = "Hello, world"; // corrected
assert( s == *p ); // this should be familiar to you, dereferencing a pointer
assert( s == r ); // this will always be true, they are twins, or the same thing rather
string copy1 = *p; // this is to make a copy using a pointer
string copy = r; // this is what you saw, hope now you understand it better.
The & character in C++ is dual purpose. It can mean (at least)
Take the address of a value
Declare a reference to a type
The use you're referring to in the function signature is an instance of #2. The parameter string& str is a reference to a string instance. This is not just limited to function signatures, it can occur in method bodies as well.
void Example() {
string s1 = "example";
string& s2 = s1; // s2 is now a reference to s1
}
I would recommend checking out the C++ FAQ entry on references as it's a good introduction to them.
https://isocpp.org/wiki/faq/references
You shouldn't know anything about pointers until you get to chapter 10 of Accelerated C++ !
A reference creates another name, an alias, for something that exists elsewhere. That's it. There are no hidden pointers or addresses involved. Don't look behind the curtain!
Think of a guy named Robert
guy Robert;
Sometimes you may want to call him Bob
guy& Bob = Robert;
Now Bob and Robert both refer to the same guy. You don't get his address (or phone number), just another name for the same thing.
In your function
void DoSomething(string& str)
{
string copy=str;
}
it works exactly the same, str is another name for some string that exists somewhere else.
Don't bother with how that happens, just think of a reference as a name for some object.
The compiler has to figure out how to connect the names, you don't have to.
In the case of assigning variables (ie, int* ptr = &value), using the ampersand will return the address of your variable (in this case, address of value).
In function parameters, using the ampersand means you're passing access, or reference, to the same physical area in memory of the variable (if you don't use it, a copy is sent instead). If you use an asterisk as part of the parameter, you're specifying that you're passing a variable pointer, which will achieve almost the same thing. The difference here is that with an ampersand you'll have direct access to the variable via the name, but if you pass a pointer, you'll have to deference that pointer to get and manipulate the actual value:
void increase1(int &value) {
value++;
}
void increase2(int *value) {
(*value)++;
}
void increase3(int value) {
value++;
}
Note that increase3 does nothing to the original value you pass it because only a copy is sent:
int main() {
int number = 5;
increase1(number);
increase2(&number);
increase3(number);
return 0;
}
The value of number at the end of the 3 function calls is 7, not 8.
It's a reference which allows the function to modify the passed string, unlike a normal string parameter where modification would not affect the string passed to the function.
You will often see a parameter of type const string& which is done for performance purposes as a reference internally doesn't create a copy of the string.
int* ptr=#
1st case: Since ptr is a memory and it stores the address of a variable. The & operator returns the address of num in memory.
void DoSomething(string& str)
2nd case: The ampersand operator is used to show that the variable is being passed by reference and can be changed by the function.
So Basically the & operator has 2 functions depending on the context.
While pass by reference may be implemented by the compiler by passing the address as a pointer, semantically it has nothing to do with addresses or pointers. in simple terms it is merely an alias for a variable.
C++ has a lot of cases where syntax is reused in different contexts with different semantics and this is one of those cases.
In the case of:
int* ptr=#
you are declaring a variable named ptr with a type of an int * (int pointer), and setting its value to the "address of the variable num" (&num). The "addressof" operator (&) returns a pointer.
In the case of:
void DoSomething(string& str)
you are declaring the first parameter of the DoSomething() method to be of type "reference to string". Effectively, this is the C++ way of defining "pass-by-reference".
Note that while the & operator operates similarly in these cases, it's not acting in the same way. Specifically, when used as an operator, you're telling the compiler to take the address of the variable specified; when used in a method signature, you're telling the compiler that the argument is a reference. And note as well, that the "argument as a reference" bit is different from having an argument that is a pointer; the reference argument (&) gets dereferenced automatically, and there's never any exposure to the method as to where the underlying data is stored; with a pointer argument, you're still passing by reference, but you're exposing to the method where the variable is stored, and potentially exposing problems if the method fails to do a dereference (which happens more often than you might think).
You're inexplicitly copy-constructing copy from str. Yes, str is a reference, but that doesn't mean you can't construct another object from it. In c++, the & operator means one of 3 things -
When you're defining a normal reference variable, you create an alias for an object.
When you use it in a function paramater, it is passed by reference - you are also making an alias of an object, as apposed to a copy. You don't notice any difference in this case, because it basically is the object you passed to it. It does make a difference when the objects you pass contain pointers etc.
The last (and mostly irrelevent to your case) meaning of & is the bitwise AND.
Another way to think about a reference (albeit slightly incorrect) is syntactic sugar for a dereferenced pointer.
I've got a C++ data-structure that is a required "scratchpad" for other computations. It's not long-lived, and it's not frequently used so not performance critical. However, it includes a random number generator amongst other updatable tracking fields, and while the actual value of the generator isn't important, it is important that the value is updated rather than copied and reused. This means that in general, objects of this class are passed by reference.
If an instance is only needed once, the most natural approach is to construct them whereever needed (perhaps using a factory method or a constructor), and then passing the scratchpad to the consuming method. Consumers' method signatures use pass by reference since they don't know this is the only use, but factory methods and constructors return by value - and you can't pass unnamed temporaries by reference.
Is there a way to avoid clogging the code with nasty temporary variables? I'd like to avoid things like the following:
scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
xyz.initialize_computation(useless_temp);
I could make the scratchpad intrinsically mutable and just label all parameters const &, but that doesn't strike me as best-practice since it's misleading, and I can't do this for classes I don't fully control. Passing by rvalue reference would require adding overloads to all consumers of scratchpad, which kind of defeats the purpose - having clear and concise code.
Given the fact that performance is not critical (but code size and readability are), what's the best-practice approach to passing in such a scratchpad? Using C++0x features is OK if required but preferably C++03-only features should suffice.
Edit: To be clear, using a temporary is doable, it's just unfortunate clutter in code I'd like to avoid. If you never give the temporary a name, it's clearly only used once, and the fewer lines of code to read, the better. Also, in constructors' initializers, it's impossible to declare temporaries.
While it is not okay to pass rvalues to functions accepting non-const references, it is okay to call member functions on rvalues, but the member function does not know how it was called. If you return a reference to the current object, you can convert rvalues to lvalues:
class scratchpad_t
{
// ...
public:
scratchpad_t& self()
{
return *this;
}
};
void foo(scratchpad_t& r)
{
}
int main()
{
foo(scratchpad_t().self());
}
Note how the call to self() yields an lvalue expression even though scratchpad_t is an rvalue.
Please correct me if I'm wrong, but Rvalue reference parameters don't accept lvalue references so using them would require adding overloads to all consumers of scratchpad, which is also unfortunate.
Well, you could use templates...
template <typename Scratch> void foo(Scratch&& scratchpad)
{
// ...
}
If you call foo with an rvalue parameter, Scratch will be deduced to scratchpad_t, and thus Scratch&& will be scratchpad_t&&.
And if you call foo with an lvalue parameter, Scratch will be deduced to scratchpad_t&, and because of reference collapsing rules, Scratch&& will also be scratchpad_t&.
Note that the formal parameter scratchpad is a name and thus an lvalue, no matter if its type is an lvalue reference or an rvalue reference. If you want to pass scratchpad on to other functions, you don't need the template trick for those functions anymore, just use an lvalue reference parameter.
By the way, you do realize that the temporary scratchpad involved in xyz.initialize_computation(scratchpad_t(1, 2, 3)); will be destroyed as soon as initialize_computation is done, right? Storing the reference inside the xyz object for later user would be an extremely bad idea.
self() doesn't need to be a member method, it can be a templated function
Yes, that is also possible, although I would rename it to make the intention clearer:
template <typename T>
T& as_lvalue(T&& x)
{
return x;
}
Is the problem just that this:
scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
is ugly? If so, then why not change it to this?:
auto useless_temp = factory(rng_parm);
Personally, I would rather see const_cast than mutable. When I see mutable, I'm assuming someone's doing logical const-ness, and don't think much of it. const_cast however raises red flags, as code like this should.
One option would be to use something like shared_ptr (auto_ptr would work too depending on what factory is doing) and pass it by value, which avoids the copy cost and maintains only a single instance, yet can be passed in from your factory method.
If you allocate the object in the heap you might be able to convert the code to something like:
std::auto_ptr<scratch_t> create_scratch();
foo( *create_scratch() );
The factory creates and returns an auto_ptr instead of an object in the stack. The returned auto_ptr temporary will take ownership of the object, but you are allowed to call non-const methods on a temporary and you can dereference the pointer to get a real reference. At the next sequence point the smart pointer will be destroyed and the memory freed. If you need to pass the same scratch_t to different functions in a row you can just capture the smart pointer:
std::auto_ptr<scratch_t> s( create_scratch() );
foo( *s );
bar( *s );
This can be replaced with std::unique_ptr in the upcoming standard.
I marked FredOverflow's response as the answer for his suggestion to use a method to simply return a non-const reference; this works in C++03. That solution requires a member method per scratchpad-like type, but in C++0x we can also write that method more generally for any type:
template <typename T> T & temp(T && temporary_value) {return temporary_value;}
This function simply forwards normal lvalue references, and converts rvalue references into lvalue references. Of course, doing this returns a modifiable value whose result is ignored - which happens to be exactly what I want, but may seem odd in some contexts.