Why does passing local variable by value work? - c++

# include <iostream>
# include <string>
using std::string;
using std::cout;
using std::endl;
string func() {
string abc = "some string";
return abc;
}
void func1(string s) {
cout << "I got this: " << s << endl;
}
int main() {
func1(func());
}
This gives:
$ ./a.out
I got this: some string
How/why does this code work ? I wonder because abc went out of scope and got destroyed as soon as the call to func() completed. So a copy of abc cannot be/should not be available in variable s in function func1 Is this understanding correct ?

The return value is copied from the local variable, effectively creating a new string object.
However, RVO (returned value optimization) should eliminate this step.
Try single stepping your code in a debugger. You should see the std::string copy constructor called for the return line. Be sure to compile with debug enabled and optimizers off.

Your code is essentially asking:
"Call func1, and in order for func1 to work I have to receive a string which we can use by calling the copy constructor on that string. The parameter for func1 we want to come from the return value of func (which we know has to be a string since its explicitly defined".
abc goes out of scope only after the copy constructor is called on the return value of func() which passes the value of the string. In theory you could have written it passed by reference or constant reference:
void func1(string& s) {
cout << "I got this: " << s << endl;
}
Which allows func1 to directly access the string in memory through a pointer (and also change it, if your code was meant to.)
void func1(string const& s) {
cout << "I got this: " << s << endl;
}
Which provides a constant reference to the string from func(). This ensures that you get a pointer to the data and that you won't change its contents. Typically passing data by constant reference (const&) is desirable because it's very fast and keeps your code from accidentally changing data that it shouldn't.
You really only need to pass by value if you're going to manipulate the data once you pass it to the new function, saving you the resources of creating another new container to handle the manipulation:
void func1(string s) {
s += " some extra stuff to add to the end of the string"; //append some new data
cout << "I got this: " << s << endl;
}

Related

C++ Some misunderstand about union

I am new to C++, and I have some questions about how the union works. This is my code :
#include <iostream>
using namespace std;
union S
{
std::string str;
int a;
~S() {}
};
int main()
{
S s {};
s.str = "hello";
std::cout << s.str << std::endl;
s.a = 3;
std::cout << s.a;
std::cout << "This is my string : " << s.str << std::endl;
}
If I write " S s" instead of " S s{}", i have a error --> use of the deleted function S::S().
if I delete this line "~S() {}", i have a error --> use of the deleted function S::~S().
In this website, https://en.cppreference.com/w/cpp/language/union,
it is said that because I have a member (string) with a non default constructor/destructor, it will delete the default constructor and the default destructor of the union S. My question is :
Why? I still don't understand why they delete the default constructor/destructor in C++.
Also, I have heard it is important to explicitly call the destructor if i want to switch the string to an integer because it will leads to the memory leak.My question is: Do I need to call the union destructor or the string destructor? In this code,if I need to call the union destructor, the destructor does nothing, so does that means my string won't be ereased?. If I need to call the string destructor, I don't know how to write the string destructor. Thank !
When i run this code, it shows me this :
hello
3
This is my string :
As I have expected, the last sentence "This is my string :" doesn't show me the string "hello" because I have overwrite "s.a = 3".
But, it seems s.str is empty. My questions is: Why does s.str is empty. Does it mean that the compiler has called automatically the destructor of my string. Thank!
I know there are alternative like boost or variant, but I still want to understand this.
If I write " S s" instead of " S s{}", i have a error --> use of the deleted function S::S().
S contains a string and this string must be constructed before it can be used. You've gotten around this with aggregate initialization which ensures the first member of the union will be correctly initialized.
Note that if a was the first member, it would be initialized rather than str and s.str = "hello"; exhibits some of that classic Undefined Behaviour action.
You could also satisfy the compiler by adding a constructor that constructed the member you wished to use as the active member. Then it doesn't matter what order. As of C++20 you can use designated initializers, S s{.str=""};, to select which member to initialize and still use aggregate initialization to avoid writing a constructor
if I delete this line "~S() {}", i have a error --> use of the deleted function S::~S().
Just as str must be constructed, you also need to have scaffolding to ensure that it can be destroyed if str is the active member when s is destroyed. This usually requires more than just a union because you need some book-keeping to track the active member. Destroying str when it is not the active member is a fatal mistake.
Also, I have heard it is important to explicitly call the destructor if i want to switch the string to an integer because it will leads to the memory leak.My question is: Do I need to call the union destructor or the string destructor? In this code,if I need to call the union destructor, the destructor does nothing, so does that means my string won't be ereased?. If I need to call the string destructor, I don't know how to write the string destructor. Thank !
Any time you stop using s as a string, before assigning to s.a or when destroying s when s is being used as a string, you need to call the string destructor to end the lifetime of str.
So
s.a = 3;
needs to become
s.str.~string();
s.a = 3;
In addition, any time you want to make str the active member, you need to make sure it is constructed.
std::cout << "This is my string : " << s.str << std::endl;
needs to become
new (&s.str) std::string("I'm Baaaaaack!");
std::cout << "This is my string : " << s.str << std::endl;
and then, because str is the active member we should destroy it before main exits.
s.str.~string();
All bundled up we get,
#include <iostream>
using namespace std;
union S
{
std::string str;
int a;
~S()
{
}
};
int main()
{
S s{};
s.str = "hello";
std::cout << s.str << std::endl;
s.str.~string();
s.a = 3;
std::cout << s.a;
new (&s.str) std::string("I'm Baaaaaack!");
std::cout << "This is my string : " << s.str << std::endl;
s.str.~string();
}

call function with cout inside a cout statement

Firstly please have a look at some simple codes that my questions derived from.
#include <iostream>
#include <string>
using namespace std;
string get_something()
{
cout << "output something";
return " and return something";
}
void print_something()
{
cout << "print something";
}
int main()
{
cout << get_something(); // will work
cout << print_something(); // will NOT work
return 0;
}
The only different thing I notice between get_something() and print_something() is that one is a return type and one isn't. As you can see I have added comments indicating that which one will work and not work.
However, I am really not sure what is happening behind the scene that makes it one possible and the other not possible.
I am not even sure how I should go about and search for this kind of question too.. so here I am asking a question.
Please enlighten me..
edit:
I am confused that how it is possible to do cout after cout..
both of the functions do that but one of them works and the other doesn't.
This seems to be a very common misunderstanding among beginners. Printing something via cout is not the same as returning a value from a function. Thats completely orthogonal things.
You can write:
std::string returned_value = get_something();
std::cout << returned_value;
But you cannot write:
??? returned_value = print_something();
std::cout << returned_value;
because print_something() does not return anything! void denotes the absence of a type. You cannot have an object of type void.
On the other hand, when you call a function, you can use the returned value (above), or you can ignore it, so this is correct code:
print_something(); // prints something
get_something(); // also print something and returned value is ignored
Note that the function get_something should get a better name, because it is not just "getting" a value. How about print_and_return_something()?
PS:
What I am really confused about is that, how is it possible to do a cout after a cout? Am I just missing what cout actually does?
Not sure If I understand, but I will try... std::cout is an object of type std::ostream. It has an operator<< that you can call, similar to calling methods of other objects. The following two are identical and just use different syntax:
std::cout.operator<<( "Hello World");
std::cout << "Hello World";
When you call print_something() then first the function is executed, then the return value is returned to the caller and execution continues with the caller. This:
std::cout << get_something();
is more or less the same as (well, its a crude simplification, but should be ok here):
// inside get_something
std::cout << "output something";
// return value
std::string result{"output something"};
// now execution continues in caller
std::cout << result;
Calling cout after cout is no different from calling some other function. Suppose you have a function print() that prints something then you can write
std::string print_and_return() {
std::string x{"Hello World"};
print(x);
return x;
}
The caller can do
std::string x = print_and_return(); // <- this already calls print()
print(x); // now we call it again
This is more or less the same as yours, just that I used some hypothetical print() instead of std::cout::operator<<.
Both your functions have a return type. It's just that one of them has a void return type.
The std::ostream class does not have an overload for << that takes a void type. This is sensible - what would be written to the stream in that case?
(cout is an instance of std::ostream that typically writes itself to the standard output which is normally the shell you're using to launch the program.)
Because print_something() has nothing to return, and cout want something to write to the console (the return value it is expecting). Therefore, it will give error.
get_something(), on the other hand, has something to return. So after executing it's rest of line (except return statement) it return the string, which gets printed by cout
get_something() returns something (what seems to be accepted by cout), so cout will receive the returned thing and will work.
On the other hand, print_something() returns nothing (because its return type is void), so cout cannot receive anything to print and won't work.
cout is a stream object.and we use << (insertion operator) to insert value like String,float,Int etc to it which will be displayed in output Screen.Since print_something() is not returning any value so nothing is inserted in stream ,That's why it is not working.
I recommend you to read about Streams in c++ ..

Variable being deallocated after function call

I'm a beginner in C++ and ran into a problem. Please see my code below. The issue is described in the inline comments.
#include<iostream>
#include<tuple>
#include<vector>
// #include "test.hpp"
using namespace std;
vector<string*> test();
int main() {
vector<string*> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: random undefined behavior
//I want this to output "s"
}
vector<string*> test() {
vector<string*> ret;
string str = "t";
ret.push_back(&str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "t"
str[0] = 's';
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "s"
return ret;
}
Basically I want to have it so that I can declare an object in a function body, add it to a vector, and be able to modify the object again later in the function (any time in the future) and be able to see these changes anywhere I have this vector. This can be easily done in Java, but I'm having trouble doing it in C++.
Objects declared with automatic lifetime always cease to exist when the scope in which they were created is left.
If you want an object to survive beyond the scope in which it was created you must create the object with dynamic lifetime, using (directly or indirectly) the new keyword. Remember though, C++ has no garbage collector, so for every use of new you must delete the created object when you're done with it. The best way to do that is to use some form of smart pointer, like std::unique_ptr or std::shared_ptr (which to use depends on your exact situation):
std::vector<std::unique_ptr<std::string>> test() {
std::vector<std::unique_ptr<std::string>> ret;
std::unique_ptr<std::string> str = std::make_unique<std::string>("t");
ret.push_back(std::move(str));
//...
return ret;
}
(std::make_unique uses new to create a new object and returns a std::unique_ptr to it)
In this particular case there's really no advantage to storing pointers to strings in your vector though. A std::string object is essentially a smart pointer to an array of characters, so you can just store the objects directly:
std::vector<std::string> test() {
std::vector<std::string> ret;
ret.push_back("t");
//...
return ret;
}
Stop using pointers. They have their place in C++ but not in the code you've posted.
The specific problem is this:
string str = "t";
ret.push_back(&str);
You are storing a pointer to a function-local std::string object. At the end of the function the std::string goes out of scope and is destroyed, leaving you with a dangling pointer and undefined behavior.
Change vector<string*> ret; to vector<string> ret;. Store objects instead of pointers, value semantics are easier to reason about. Standard library containers and strings are designed to do the right thing and make all of this simple.
You want to change this:
string str = "t";
ret.push_back(&str);
To this:
string* str = new string("t");
ret.push_back(str);
The problem is that in your original example your string gets destroyed when you exit test(), meaning that its memory address now points at nothing. To avoid this, you want to allocate str on the heap by using a pointer so that the memory isn't cleaned up after you exit test().
Just remember that whenever you manually allocate memory in C++, you must deallocate it to avoid memory leaks:
for (string* i : ret) {
delete i;
}
You are pushing back the address of a local variable. When the variable goes out of scope, that memory address is freed.
You can use unique_ptr or shared_ptr instead, something like this:
#include<iostream>
#include<tuple>
#include<vector>
#include<memory>
// #include "test.hpp"
using namespace std;
vector<std::shared_ptr<string>> test();
int main() {
vector<std::shared_ptr<string>> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
}
vector<std::shared_ptr<string>> test() {
vector<std::shared_ptr<string>> ret;
const auto str = std::make_shared<string>("t");
ret.push_back(str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
return ret;
}

C++ class and friend [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions must demonstrate a minimal understanding of the problem being solved. Tell us what you've tried to do, why it didn't work, and how it should work. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
This is my code:
#include <iostream>
#include <string>
using namespace std;
class C
{
private:
string str;
friend void func();
};
void func()
{
str = "Lala";
cout << str << endl;
}
int main()
{
func();
}
I don't understand why this doesn't work.
In my bigger project I want to acces private variables of a class with a function out of class.
Here I made a class C and made a function func(); to be its friend.But still I can't use it's private variables in function.
What I did wrong and is there a better way to do this?
It doesn't work because void func(); is not a member function of the class, it's just declared as a friend function to it, meaning it can access the private members.
You have no instance of the class C, so you can't possibly refer to any valid str variable.
Next time, please also quote the errors you get. In this case, there will be a compile error stating the symbol "str" has not been defined within func().
If you want to access the member str of a class instance of C, you need such an instance, as in:
void func(){
C c;
c.str = "Lala";
cout << c.str << endl;
}
func() is not a member function, and it is not receiving any parameter of type C, what object is it supposed to operate on?
func must either be a member function of C (in which case you'll invocate it over an instance of C, and friend is not necessary), either a function that receives some parameter of type C (or create a local C object), on which it can work on, even accessing its private fields.
This doesn't work since str is not defined inside func().
You should have an instance of C.
void func()
{
C foo;
foo.str = "Lala";
cout << str << endl;
}
If you need to you can pass the C instance as a parameter:
void func(C &foo)
{
foo.str = "Lala";
cout << str << endl;
}
The problem
Let's look at your code piece by piece:
#include <iostream>
#include <string>
using namespace std;
Just a short note here: It is a bad idea to use using namespace std;.
class C
{
private:
string str;
friend void func();
};
Here you define a class C. You declare that objects of this class will contain a string, which is private (i.e. may only be accessed by class members and friends), and you declare the global function void func() a friend, that is, it is allowed to access the private members (in this case str) of the class C and of any object of type C. Note that apart from that permission, func is in no way related to the class C.
void func()
{
str = "Lala";
cout << str << endl;
}
Here you try to assign to a variable str which you never declared. Remember that there's no relation of func to the class C other than that it may access the private members of
C and objects of type C. However, there's no object of type C in sight, and even if there were, there's nothing to tell the compiler from which object str is to be taken, or even that you are speaking about the str in C. I'll remember you again that func is completely independent of C, so the code is interpreted the same way as if C wouldn't have declared it a friend.
int main()
{
func();
}
OK, nothing special here, you're just calling func.
How to fix it
Now, how to fix your code? Well, there are several possibilities:
Supplying objects
Local objects
Since str is a member of objects of class C, you'll need an object of the class. So you could for example do:
void func()
{
C object;
object.str = "Lala";
std::cout << object.str << std::endl;
}
Here you create a local object in func, assign to that object's str member a value and then outputs it. To see that different objects have different members, you can e.g. write:
void func()
{
C object1, object2;
object1.str = "Lala";
object2.str = "Lele";
std::cout << object1.str << " -- " << object2.str << "\n";
}
This outputs Lala -- Lele because the first object's str member has the value "Lala" while the second object's str member has the value "Lele".
Function arguments
Another option is that you pass the object as argument, e.g.
void func(C object)
{
std::cout << object.str << " -- ";
object.str = "Lele";
std::cout << object.str << " -- ";
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
std::cout << object.str << std::endl;
}
This prints Lala -- Lele -- Lala.
What happens here is that in main an object is created, whose str member is assigned the valeu "Lala". On call to func, a copy of that object is created, which you then access from func. Since it's a copy, it initially also contains the same value "Lala", whichfuncthen outputs. Then the assignment infuncchanges thestrmember *of that copy* to"Lele"and outputs that. The original object is not affected as the output inmain` shows.
So you see, there can be several objects, and it is crucial that you say the str member of which object you want to access.
Now if you do not intend to change the object in the called function, making a copy is just a waste of time, therefore you can also pass it as a reference to const:
void func(C const& object)
{
std::cout << object.str << std::endl;
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
}
The argument C const& says "I want to directly access the object the caller gives me, but I promise not to change it." The "directly access" part is denoted by the &, and the "I promise not to change it" is denoted by the const. The compiler actually checks that you hold your promise and don't try to change it (that is, if in func you tried to do object.str = "Lele", the compiler would complain (there are ways to tell the compiler to shut up about that, but you shouldn't do that; just keep your promises). However note that this applies again only to that specific object; for example, the following code is completely OK:
void func(C const& object)
{
C another_object;
another_object.str = "Lele";
std::cout << object.str << " -- " << another_object.str << std::endl;
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
}
This gives no error and prints Lala -- Lele because you're dealing again with different objects.
Of course there may be the case that you do want to change the object you are passed. Then you can just use & without const:
void func(C& object)
{
std::cout << object.str << " -- ";
object.str = "Lele";
std::cout << object.str << " -- ";
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
std::cout << object.str << std::endl;
}
This prints Lala -- Lele -- Lele.
Now you again directly access the object passed as argument from main, but this time, you don't promise that you don't change it, and indeed you do change it. The output from main demonstrates that indeed main_object was changed.
Making the variable a static member
Now, there's the possibility that you really want there to only ever be one str in C, not a separate one for each object of that type. If you are absolutely positive that this is what you want, then you can make str a static member of the class:
class C
{
private:
static std::string str; // note the keyword "static" here
friend void func();
};
std::string C::str; // You have to have an extra definition for class static variables!
Now you can access str without having an object of C available. However note that you still need to tell the compiler inside func that you want to access the str inside C:
void func()
{
C::str = "Lala";
std::cout << C::str << std::endl;
}
You can also access the variable on object as if it were a member of that object. However be aware that this does not mean that different objects still have their own str. For example, with the changed class definition, we will gett different behaviour for the code from above:
void func()
{
C object1, object2;
object1.str = "Lala";
object2.str = "Lele";
std::cout << object1.str << " -- " << object2.str << "\n";
}
Now we will get the output Lele -- Lele because there's only one str, which does not depend on the object (the syntax object1.str in this case is misleading in that respect; actually here it means "the str defined for the type of object1, that is, C").
void func(C* object)
{
object->str = "Lala";
cout << object->str << endl;
}
Since func is not a member of the class, so you can't call it like object.func(). Thus the function won't know which object of the class you wish to change. So you have to explicitly pass the object pointer to the function. Use a reference would also do.
Or you can declare str as static. But static member will make all instances of the class share the same value.

Constructing a temp object and calling a method that returns a pointer - is it safe?

My intution says it isn't, but the fact that everything is going on in the same line is a bit confusing. I wonder if the pointer is still valid when cout uses it.
#include <iostream>
#include <string>
struct A {
A() : m_s("test"){ }
const char* c_str() { return m_s.c_str(); }
std::string m_s;
};
int main() {
std::cout << "abc " << A().c_str() << " def" << std::endl;
}
Yes, it is safe. The temporary A() is destroyed at the end of the statement. That is after cout used the pointer returned.
The value returned by c_str() is valid as long as the std::string it was obtained from is unchanged and has not been destroyed. So your code is perfectly OK, as the temporary you create will have a lifetime equivalent to the full expression (the cout chain in this case) that it is part of.
It is safe provided content doesn't change in between the call.
The address that is returned, is indeed pointing to valid location of the char*.