In a logging context, I would like to use a temporary instance of a utility class to collect some output, and use the destructor to dispose of the collected output. For example, printing to standard output as below.
I am noticing behavior differences depending whether the utility instance is constructed as an inline, anonymous instance as compared with a named automatic instance.
The named instances result in expected behavior and output. The inline instances have difficulty with the first insertion operation, apparently only working on operands which have simple conversions to int.
What is the difference between instances used in these different ways?
#include <string>
#include <sstream>
#include <iostream>
class Util
{
public:
std::ostringstream m_os;
Util() {}
~Util() { std::cout << m_os.str() << std::endl;}
};
int main (void)
{
// ----------- Using temporary anonymous instance -
// Output does not match expected, and the first insertion seems to
// only be able to handle instances that can be converted to int.
// Following prints "97key=val", but expect "akey=val"
(Util()).m_os << char('a') << std::string("key") << "=" << std::string("val");
// Following prints "0x80491eakey=val", but expect "Plain old C string key=val"
(Util()).m_os << "Plain old C string " << std::string("key") << "=" << std::string("val");
// Following results in syntax error
// error: no match for ‘operator<<’ in ‘Util().Util::m_os <<
(Util()).m_os << std::string("key") << "=" << std::string("val");
// ----------- Using named instance - output matches expected
// Block results in print "akey=val"
{
Util inst;
inst.m_os << char('a') << std::string("key") << "=" << std::string("val");
}
// Block results in print "Plain old C string key=val"
{
Util inst;
inst.m_os << "Plain old C string " << std::string("key") << "=" << std::string("val");
}
// Block results in print "key=val"
{
Util inst;
inst.m_os << std::string("key") << "=" << std::string("val");
}
return 0;
}
(Util()) creates a temporary object. As a result, (Util()).m_os is also a temporary object.
There are some definitions of operator<< as a member function, and some other definitions of it as a freestanding function. The former work on temporary objects, the latter does not, because a temporary cannot be bound to a reference-to-stream. Simplifying your code to a full example:
#include <stdio.h>
struct stream
{
stream& operator<<(int)
{ puts("operator<<(int)"); return *this; }
};
stream& operator<<(stream& s, char)
{ puts("operator<<(char)"); return s; }
struct streamwrapper
{
stream s;
};
int main()
{
streamwrapper w;
w.s << 'a'; // outputs operator<<(char)
streamwrapper().s << 'a'; // outputs operator<<(int)
}
Since the overloads you expected are unavailable, yet others are not, those other overloads get used instead of giving you a hard compiler error.
Related
Little known feature of C++ is ref-qualifiers for member functions.
It works as I expect it to work in most cases, but it seems that std::optional does not forward the knowledge of its imminent demise to contained object member functions.
For example consider the following code:
#include <chrono>
#include <iostream>
#include <optional>
struct Noisy {
Noisy(const std::string& data): data_(data){
}
~Noisy(){
std::cout << "Goodbye" << std::endl;
}
std::string data_;
const std::string& data() const & {
std::cout << "returning data by ref" << std::endl;
return data_;
}
std::string data() && {
std::cout << "returning data by move" << std::endl;
return std::move(data_);
}
};
int main() {
for (const auto chr: Noisy{"Heeeeeeeeeeeeeeeeello wooooorld"}.data()){
std::cout << chr;
}
std::cout << std::endl;
for (const auto chr: std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}->data()){
std::cout << chr;
}
std::cout << std::endl;
}
output is:
returning data by move
Goodbye
Heeeeeeeeeeeeeeeeello wooooorld
returning data by ref
Goodbye
(crash in clang with sanitizer or garbage(UB))
I was hoping that temporary std::optional will be kind enough to call correct (data() &&) function, but it seems it does not happen.
Is this a language limitation, or std::optional just does not have correct machinery for this?
Full godbolt link.
note: my motivation is hacking around to see if I can be clever to enable safer usage of my classes in range based for loop, but realistically it is not worth the effort, this question is mostly about learning about language.
Overloaded operator arrow cannot do what you want; it terminates with a pointer always.
x->y is defined by the standard as (*x).y if and only if x is a pointer; otherwise it is (x.operator->())->y. This recursion only terminates if you hit a pointer.1
And there is no pointer to temporary type. Try this:
const auto chr: (*std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}).data()
Which does call the rvalue method. (via #largest_prime).
1 This recursion can also do Turing complete computation.
i'm trying to write a logging class where you will be able to do something like this
//Create an instance of a class
Log log;
log.debug() << "a string " << 42 << endl;
log.info() << "another string " << 41 << endl;
This will produce the following output to stdout
Info: a string 42
Debug: another string 41
Here is what i have been able to achieve so far
#include <iostream>
#include <string>
#include <sstream>
#define endl '\n'
using std::cout;
using std::string;
using std::stringstream;
class Log {
public:
Log () {}
~Log() {}
//Create buffer to store everything
stringstream buffer;
//Create templase class to overload <<
template <class T>
inline Log & operator << (T data) {
buffer << data;
return *this;
}
inline Log & debug() {
print("Debug: ");
}
inline Log & info() {
print("Info: ");
}
inline void print(string type) {
//Display the contents of the buffer to standard output
cout << type << buffer.str();
//Clear the buffer
buffer.str(string());
}
};
int main() {
Log log;
log << "Hello " << "World " << 5 << " " << 2.3 << endl;
log.debug();
log << "Hello Again " << 42 << endl;
log.info();
return 0;
}
This produces the correct output but this way each line of logging takes up two lines of code and is very cumbersome. Can anyone thing off a way I can do log.debug() << "stuff"? This is a very simple example, in later versions, instead of just a string there will be time stamps, date stamps, usernames etc. which is why i'm trying to get each log level handled by a different function.
I am guessing I'll need another operator overload statement but i just can't figure out what it needs to be. Also the current << template operator doesn't like std::endl (wont compile if i use it) so I just set endl = '\n' at the top.
Thanks in advance, looking forward to learning as much as possible.
It sounds like what you want is for your debug and info functions to return something like a std::stringstream that will support operator<<, but somehow also flush the output afterwards. If that's it, you would be better off using something like a variadic template function.
As for your other issue, std::endl is actually a template, so its type cannot be used as T for Log::operator<< <T> (T). This is one example of why it's not worth trying to reimplement the stream functionality. The overload which lets you write << std::endl is declared something like template <class _CharT, class _Traits> basic_ostream<_CharT, _Traits> & operator<<(basic_ostream<_CharT, _Traits>&, basic_ostream<_CharT, _Traits> &(basic_ostream<_CharT, _Traits> &)). std::endl is a function template which takes an ostream, appends a newline, and flushes the stream.
I should also note that your debug and info functions are not returning a value. If you're using GCC, the warning for this is disabled by default but it can be a very tricky source of undefined behavior. Use -Wreturn-type to enable it when you build something important.
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Printing a string to a temporary stream object in C++
std::ostringstream printing the address of the c-string instead of its content
I'm trying to build up a string using stringstream, in the same way you'd use cout. This for something like a logging class. The issue I'm having is that if the first argument to the << operator is a string, when I subsequently print out that stringstream with the stringstream::str() call, I get a garbage address, and not the string. This only occurs with the FIRST string. Subsequent strings are fine. Numbers are always fine. Here's the code:
// class I use to print out the stream
class StreamWriter
{
public:
StreamWriter()
{}
~StreamWriter()
{
std::string myMessage = m_stringstream.str();
std::cout << myMessage << std::endl;
}
std::stringstream m_stringstream;
};
// macro for simplification
#define OSRDEBUG (StreamWriter().m_stringstream)
// actual use
OSRDEBUG << "Hello " << "my " << "name is Pris " << 123456;
// output
0x8054480my name is Pris 123456
0x8054480my name is Pris 123456
0x8054480my name is Pris 123456
0x8054480my name is Pris 123456
Could anyone shed some light on what's going on, and how I could get around the issue?
EDIT:
The following changes (in addition to padiablo's examples) works as well, maintaining the use of the class's destructor with the macro.
// class I use to print out the stream
class StreamWriter
{
public:
StreamWriter()
{ m_stringstream = new std::stringstream; }
~StreamWriter()
{
std::string myMessage = m_stringstream.str();
std::cout << myMessage << std::endl;
delete m_stringstream;
}
std::stringstream * m_stringstream;
};
// macro for simplication
#define OSRDEBUG *(StreamWriter().m_stringstream)
The original question still stands though, because it looks like it should work... and I think it's probably important to know when the times comes to put this into production-quality code.
The problem is indeed that the stream is a temporary.
Before C++11, there was no non-member operator<< overload that took an rvalue reference as the first parameter (aka, allowing writes to temporary streams).
As such, the only valid operator<< overloads were the members, since all non-member overloads take a non-const reference and as such will not bind to temporaries. One of those non-member overloads is the one responsible for printing C strings (aka char const*). Here's one of the member overloads:
basic_ostream<Ch, Traits>& operator<<(void* p);
And guess what your string literal liberally converts to. :)
After the first string, you get a normal reference back from the call to operator<<, which will then allow the non-member overloads to be viable.
I honestly don't understand exactly what's going on (it has something to do with your StreamWriter instance being a temporary), but I see the same effect as paxdiablo described in both GCC and MSVC.
However, here's something that can work around the problem. Add the following helper to your StreamWriter class:
ostream& get_ostream() {
return m_stringstream;
}
and change the macro to:
#define OSRDEBUG (StreamWriter().get_ostream())
I have tried a couple of alternatives, and the only thing I got working is something like this:
#define OSRDEBUG(s) \
do \
{ \
StreamWriter writer; \
writer.m_stringstream << s; \
} while (0)
OSRDEBUG("Hello " << "my " << "name is Pris " << 123456);
I have personally used the above construct for my own logging solutions many times, and seen it done by others as well.
I'm not good enough to know why your example doesn't work, but I guess it has something to do with temporaries not staying alive long enough.
It appears to be a consequence of the way you're instantiating the object. I'm still investigating (and you may get a better answer in the meantime) but explicitly instantiating the object works fine:
#include <iostream>
#include <sstream>
class StreamWriter {
public:
StreamWriter() {}
~StreamWriter() { std::cout << m_stringstream.str() << std::endl; }
std::stringstream m_stringstream;
};
int main (void) {
StreamWriter *sw = new StreamWriter();
sw->m_stringstream << "Hello " << "my " << "name is Pris ";
delete sw;
return 0;
}
As does instantiating on the stack as well:
int main (void) {
StreamWriter sw;
sw.m_stringstream << "Hello " << "my " << "name is Pris ";
return 0;
}
Both of those print out what you expect but the following simplification of your code does not:
int main (void) {
StreamWriter().m_stringstream << "Hello " << "my " << "name is Pris ";
return 0;
}
If you're just after a solution, you can probably get by with:
#define ORSDEBUG StreamWriter sw; sw.m_stringstream
and ensuring you scope-protect the command so that it doesn't try to create more then one sw, and also that it's destroyed at the correct time, same as your original attempt:
{ ORSDEBUG << "Hello " << "my " << "name is Pris"; }
I snipped the irrelevant parts out of my class here. I don't know what I'm doing wrong, just trying to be able to cout << the object.
#include <iostream>
class Snipped
{
public:
friend std::ostream& operator<<(std::ostream& os, const Snipped& s);
protected:
private:
};
std::ostream& operator<<(std::ostream& os, const Snipped& s)
{
os << "test";
return os;
}
int main(int argc, char* argv[])
{
Snipped* s = new Snipped();
std::cout << s << std::endl << s;
delete s;
return 0;
}
Expected output:
test
test
Actual output:
0x12ae20
0x12ae20 (random memory location?)
std::cout << s << std::endl << s;
You are calling << with an address, you need to call it with object of type Snipped.
The line of code above won't call your overloaded operator function because the parameters of the overloaded function do not match.
You need to call:
std::cout << *s << std::endl << *s;
This ensures your << overloaded operator function is called because the parameters match to it.
Try
std::cout << *s << std::endl;
By the way,
std::cout << s << std::endl;
is not really a random memory location.
It is the actual memory address on the heap, in this case.
You can actually use that address to check the identity of an object.
That's useful while debugging, or in actual code.
For example, if you look at assignment operators, you will often see:
class Foo
{
Foo& operator=( const Foo& foo )
{
// use the identity principle
if ( &foo==this )
return *this; // so I don't waste CPU cycles copying to myself
// ...really do copy here
return *this;
}
};
Although just dereferencing the pointer (i.e. to use '*s' instead of 's') there is a bigger fish to fry! Unless there is a good reason for putting an object on the heap you shouldn't do so:
int main()
{
Snipped s;
std::cout << s << '\n' << s;
}
I found the use of new and more so delete quite rare in the programs I write. Aside from simpler code this conveniently also often yields faster programs. If you really need to allocate something on the heap, use some sort of a smart pointer to make sure the object is automatically released:
int main()
{
std::unique_ptr<Snipped> s(new Snipped);
std::cout << *s << '\n' << *s;
}
As a side note, don't use std::endl either unless you really intend to flush the stream: I found inappropriate use of std::endl to be the root cause of massive performance problems more than once. Sure most of the time it doesn't matter but in even more cases you don't care about the flush. If you don't like using '\n' or "\n" you can instead use a custom manipulator:
std::ostream& nl(std::ostream& out) { return out << '\n'; }
With this you can use nl instead of std::endl and don't suffer from always flushing the stream.