I have the following program in which the private string mOutStr is filled with characters in method "FetchSessionStatus".
After that, if mOutStr is empty (aka: FetchSessionStatus doesn't fill it or some other error happened) mOutStr is replaced by a "default string" called mAliveMsg.
Finally mOutStr is passed by reference to method OnCommand. OnCommand writes the string inside a pipe and then should clear mOutStr. However, the clean never works: mOutStr remains filled.
void RtnodeSpvSession::EnqueueRead()
{
std::string sCmd;
FetchSessionStatus();
(mOutStr.empty()) ? sCmd = mAliveMsg : sCmd = boost::ref(mOutStr);
OnCommand(sCmd);
}
void RtnodeSpvSession::OnCommand(std::string& sCmd)
{
std::cout << "Sending message " << sCmd.c_str() << " of "<< sCmd.size() << " size\n";
write(fd[1], sCmd.c_str(), sCmd.size());
sCmd.clear();
}
//Simplified version of FetchSessionStatus
void RtnodeSpvSession::FetchSessionStatus()
{
mOutStr+="x";
}
The end result is that, cycle by cycle, mOutStr keeps increasing in size, which means sCmd.clear is not working (aka the pass by reference is not working) but I don't understand what I'm supposed to do.
Well the issue here is that you're not passing the string you think by reference.
In your case, boost::ref return a reference wrapper to mOutStr, however, when you assign it to sCmd, it'll copy the content of mOutStr into sCmd.
In your OnCommand function, sCmd is a reference to sCmd in RtnodeSpvSession::EnqueueRead, not to mOutCmd. If you want to clear mOutCmd, you have to either do it in EnqueueRead, or to actually pass it to the OnCommand function.
For clarification, reference_wrapper<T> offer an implicit conversion to T&, but std::string::operator=(const &str) does a copy of str into the left operand, and do not replace said operand.
Related
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++ ..
# 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;
}
I'm working through some SDL2 tutorials and I just got up to a part where you start building a error logger. The entire code is:
void logSDLError(std::ostream &os, const std::string &msg){
os << msg << " error: " << SDL_GetError() << std::endl;
}
After awhile I realized what "std::ostream &os" did but I don't understand why the & and the const are necessary with the string. Why are they required? I know that if I don't use them it throws an error. In case it's important this is a snippet of the code that would use this function:
if (loadedImage != nullptr){
texture = SDL_CreateTextureFromSurface(ren, loadedImage);
SDL_FreeSurface(loadedImage);
//Make sure converting went ok too
if (texture == nullptr) logSDLError(std::cout, "CreateTextureFromSurface");
}
If your function header looks like this:
void testfunction(std::string msg), and you call it, it will be created a copy of the string thus taking up more space. If you want to either save memory or use the actual memory location of the string, you should do:
void testfunction(std::string &msg);
Although, this is dangerous when you do not want to modify the string, that's why one should use
void testfunction(const std::string &msg);
when you do not want to use any additional space, but you don't want the string to editable in the function.
Why are they required?
The const and & are used to pass the string message by constant reference so that you can save a copy of the string. The reference is to avoid the copy, and the const is to prevent you from edit it.
I know that if I don't use them it throws an error.
No, it won't throw any error related to the function argument.
I don't understand why the & and the const are necessary with the string.
& means you're passing by reference rather than value; const means the function can't use the reference to modify the string. Your introductory book should explain reference and value semantics in detail.
I know that if I don't use them it throws an error.
You could remove both (or just &) and pass by value without error; but that might be less efficient since the string will typically have to be copied.
If you remove const but leave & (passing by non-constant reference) then you wouldn't be able to pass a temporary string to the function, as your example does. Temporaries can only be bound to constant references.
I have this function which should take an optional stream argument to print as an errortext.
void showUsage(std::wstringstream oErrortext, bool bExit, int nExitCode)
{
if(oErrortext.rdbuf()->in_avail() > 0)
std::wcerr << oErrortext << std::endl;
std::wcout << gUsage << std::endl;
if(bExit == true)
exit(nExitCode);
}
Now when I try to call this with a single argument, it works fine:
showUsage(std::wstringstream(L"Multiple filenames for target found"), true, 10);
But the reason why I wanted to use stringstream is, to be able to construct a generaetd string, not just static strings.
Example:
showUsage(std::wstringstream(L"Number format for offset missing -") << oParam->mOption, true, 10);
But I get a compilation error with this.
How can I create this temporary object and stream the parameters with a single line (or do I have to create it first anyway so it wouldn't be possible with a single line)?
Is there a better solution to what I'm trying to do here (not messing with varargs)?
You can use a string instead of a stream:
void showUsage(std::wstring oErrortext, bool bExit, int nExitCode)
{
if (!oErrortext.empty())
std::wcerr << oErrortext << std::endl;
...
}
To use it, concatenate strings with +:
showUsage(std::wstring(L"Number format missing -") + oParam->mOption, true, 10);
My system has an incompatible return type for operator<< of stringstream (it returns a reference to ostream, not a reference to stringstream), so it's impossible to append stuff to a stringstream and send it to a function in a single line of code (it might be possible to use a static_cast, but you certainly don't want this ugly hack). So, unless this is an implementation bug (unlikely!), you must do large changes your code, like suggested above.
I propose you to use a reference for the stringstream:
std::wstringstream& showUsage(std::wstringstream& oErrortext, bool bExit, int nExitCode)
(note the &)
Copying streams seems to be an issue. (Thinking of what happens with source and destination...)
If you pass it like you did, a copy of the string is needed. You can avoid this by call by reference.
void outputString(const string &ss) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
int main(void) {
//! outputString("ambigiousmethod");
const string constStr = "ambigiousmethod2";
//! outputString(constStr);
} ///:~
How to make distinct call?
EDIT: This piece of code could be compiled with g++ and MSVC.
thanks.
C++ does not allow you to overload functions where the only difference in the function signature is that one takes an object and another takes reference to an object. So something like:
void foo(int);
and
void foo(int&);
is not allowed.
You need to change the number and/or the type of the parameter.
In your case the function that accepts a reference, you can make it accept a pointer, if you want to allow the function to change its argument.
You could change the signature of one of the methods. It may not look pretty, however it is the simplest way.
So you could in principle have
void outputString(const string &ss, int notneeded) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
and when you want to call the first function just call it with:
outputString("ambigiousmethod", 0);
which will result in a distinguishing call.
There is no other way (I'd love to be proven wrong on this one) since C++ does not allow overloading where passing (by value or by reference) is the only difference in signature.
Edit: as pointed out by bzabhi, you could also change the signature by changing the reference to a pointer. In the example you gave that would work, however you may have to change function code on some occasions.
According to your code, u need only
void outputString(const string &ss).
Because both methods cannot change the argument to the caller (because it's const reference or by-value passing).
Why do you need those 2 methods?
I recommend using the techinque of giving each and every function a unique name., i.e., do not use syntax overloading. I have been using it for years and I've only found advantages in it.