Unique_ptr out of scope - c++

I'm having an issue passing unique_ptrs to functions, it seems they go out of scope when I pass to askQuestion.
hears my code.
char askQuestion(string *questions[8], unique_ptr<binaryBase>answered) {
bool asked = false;
char input = '0';
while (!asked) { // loop until you find a question that has not been asked
int randomQuestion = (rand() % 8); // generate a random number
if (!(answered->getBit(randomQuestion))) { // check if the question has been answered
getInput(input, *questions[randomQuestion]);
answered->toggleBit(randomQuestion);
asked = true;
}
}
return input;
}
these two functions access unique_ptrs, function below relies on function above for input.
when I call askQuestion I get "(variable) cannot be referenced -- it is a deleted function"
bool checkAnswer(char answer, int place, binaryBase* reference) {
/* if the answer is T and the correct answer is true, returns true
if the answer is F and the correct answer is false, returns true
return false otherwise
*/ return((answer=='T'&&reference->getBit(place))||(answer=='F'&&!reference->getBit(place)));
}
binaryBase is a simple custom class and only has a 8 int as data and getters and setters for bits, this treats the 8 bit int as a byte to store "boolean" answers for the program.

I'm not seeing a call to askQuestion() in your example. However, I can see that askQuestion() is an "observer" of the answered parameter. A unique_ptr is used to transfer ownership of a pointer, not for just observing it. So you should define that function as:
char askQuestion(string *questions[8], binaryBase& answered)
instead. Use a reference here instead of a pointer to make it clear that passing null is not allowed. (Of course change all occurrences of answered-> to answered.)
When you call that function and want to pass an object managed by a unique_ptr<binaryBase> ptr, then pass the managed object, not the unique_ptr itself with *ptr.
In cases where you actually do want to transfer ownership of the pointer, then you need to move the pointer:
void func(std::unique_ptr<binaryBase>);
// ...
std::unique_ptr<binaryBase> ptr = /* ... */
func(std::move(ptr));
After the call to func(), ptr does not contain an object anymore. func() took ownership of it.
unique_ptr is a "move-only type". It cannot be copied because its copy constructor and copy assignment operator have been deleted, which is the reason of your original compilation error.

char askQuestion(string *questions[8], unique_ptr<binaryBase>answered)
You are attempting to pass a std::unique_ptr by value to askQuestion() but it's a move-only type. It represents a dynamically allocated object that is not shared by more than one object at a time. You can only move a unique_ptr or pass it by reference. If you intend to pass ownership of the unique pointer then you have to use std::move:
askQuestion(questions, std::move(answered));
where answered is a std::unique_ptr<binaryBase>. Once ownership has transferred to a function then the caller cannot use that unique pointer again.
If you do not want to pass ownership then it can be passed by reference. Change askQuestion() to do that:
char askQuestion(string *questions[8], unique_ptr<binaryBase> &answered); //non-const lvalue reference
or
char askQuestion(string *questions[8], const unique_ptr<binaryBase> &answered); //const lvalue reference
When passing by reference the function can use the pointer but not own it, unless you explicitly use std::move within the function with a non-const lvalue reference unique pointer (a const lvalue reference can't be moved).
bool checkAnswer(char answer, int place, binaryBase* reference)
In your code you are passing a pointer to binaryBase to the function checkAnswer(). Again there's no need for this function to own the unique pointer, so you can pass the unique pointer by reference as shown above or use std::unique_ptr's get() method to get a pointer to the object.
You might like to check out this answer, which deals with different ways of passing a unique pointer comprehensively.

Related

How to pass the unique pointer to specific param required in function?

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.

Pointer address as reference in function

I've got one general question, why can't I pass the the pointer's address as a reference?
void domdom(string &foo)
{
foo = "";
}
string fooso = "blabal";
string* p_fooso = fooso;
domdom(p_fooso); // <-- why is that not possible? And what should I pass to be able to modify foosoo?
I know I could change the function domdom to accept (string* foo), but is it also possible to modify the string fooso in the function by using the pointer to it and the given function?
why can't i pass the the pointer's address as a reference?
Because that's how the language is defined.
Instead, you can dereference the pointer to get a reference to the string:
domdom(*p_fooso);
or, pass the actual object directly:
domdom(fooso);
Also note that string* p_fooso = fooso; doesn't compile. You have to write string* p_fooso = &fooso;.
Just declare p_fooso as a string reference type.
You might want to rename variable as r_fooso!
string& r_fooso=fooso;
Pointers and references are similar under the hood, but are used differently, which is why mixing them by implicit conversion is not allowed by C++, to avoid confusion.
However you can always explicitly convert a reference to a pointer, and vice versa, without incurring the overhead of a copy. For example, if you call the function as domdom(*p_fooso), you will get the desired effect, i.e. the function will receive reference to the exact object you'd get by dereferencing the pointer.

I have a misconception with pointers in C++

Please find my code-snippet below:
void inpu(vector<vector<int>> &pairs,int I){
//Do something
}
int main() {
int I = 10;
vector<vector<int> > pairs(N);
inpu(pairs,I);
}
Now, I understand that the function inpu() expects an address of a vector type and an integer. My doubt is that when calling inpu(), why are we not passing an address of the vector pairs, as inpu(&pairs,I); in int main(), but as inpu(pairs,I);?
Because you do not pass the object's address (a pointer). You pass the object itself (via a reference). Ampersand in the declaration of function argument is the syntax to distinguish that you want the object itself rather than a copy.
// This will copy the pairs
void inpu_c(vector<vector<int>> pairs){
}
// This will work on the original object
void inpu_r(vector<vector<int>> &pairs){
}
The pointer can be used as a reference type, you can dereference it and use the original object itself.
// This will work on the pointer
void inpu_p(vector<vector<int>>* pairs){
pairs->clear();
(*pairs).clear();
// You can even use a reference type inside, you have to dereference a pointer
assert(pairs); //Some protection against invalid pointers
// a reference type requires an object
vector<vector<int>>& r = *pairs;
// will clear object pointer by pairs
r.clear();
}
Using pass-by-value and pass-by-copy semantics do not change the client syntax though. The client code looks the same. That is why you don't have to use get-address operator (&) on the call site.
Pointers are slightly different from references, those two are different data types. E.g. pointer is nullable, i.e. has a special designated invalid value, while reference is designed to always point to an object.

Converting a Pointer to Reference, Costly? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How expensive is it to dereference a pointer in C++?
If I've got a pointer to an object, let's say Object *ptr;, and I want to pass that to a method of the form void foo(Object& obj) I understand that I need to write:
foo(*ptr);
But why dereference ptr? Wouldn't it make sense to just pass it foo(ptr);? I'm worried *ptr might be making a copy of the original object, or at the least not merely passing to foo the address to work with.
Can anyone clear this up for me? Is passing *ptr a potential bottleneck, for code that expects this to behave just as fast as if the function had been void foo(Object *obj); and called via foo(ptr)?
Whether passing *ptr does make a copy or not depends on whether the called function expects an Object or an Object &.
In the former case, a copy would be made. In the latter case (i.e., your case), no copy would be made.
I'm worried *ptr might be making a copy of the original object.
You're wrong. Dereferencing a pointer doesn't make any copy!
void f(Object & obj); //note it takes the argument by reference
Object *ptr = get();
foo(*ptr);
At the last line of this code there is no copy. The Standard gives you that guarantee.
However, if f takes the argument by value, then there will be copy.
The bottomline: the reference in the function parameter is used to avoid copy (often) or as ouput parameter (occasionally)!
Passing an object by reference just passes the pointer so foo(*ptr) is correct and won't copy the object. Why dereference it? Because the function signature wants an object, not a pointer to an object. C++ is a strongly typed language.
To pass reference to a function, you have to pass the object like you do in value semantics. Pointers are not references since they are entity semantics (addresses).
If you dereference a pointer, you get an actual value, that can be embedded as a reference.
References and Pointers are the same. But References have their own advantage and that is they can not be null ( though they can but it's kinda hard to make a null reference ) so you can omit the check against the nullptr. You can use . instead of -> which is a character shorter xD. About your question since the pointers are references are the same in the end there won't be any gains choosing one over the other. I mean the codes bellow are the same when compiled.
void foo(int &r) {}
and
void foo(int *p) {}
when you use a reference there will be a dereferencing in the background.
Hope it helped.

Use of the & operator in C++ function signatures

I'm currently reading through Accelerated C++ and I realized I don't really understand how & works in function signatures.
int* ptr=&num;
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=&num;
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=&num;
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.