I ran across a class with a member var as a reference (to a std::istream), with operator void *() and bool operator !() that return that reference, and i'm wondering what that would be for. The class is related to reading/parsing text files with config param pairs. I've pulled out from the (much) larger project the basic parts. In qt (MSVC 2015 community tool chain), i had to change the operator void *() to get a compile, but seems ok on the original linux system.
(In my desktop environment i get: "error: C2440: 'return': cannot convert from 'std::istream' to 'void *'", so i replaced with a call to if(m_in.eof()) and return nullptr)
class LR { // (line reader)
public:
LR(const std::string &filename);
.... other stuff
operator void *() const { return &m_in; }
bool operator !() { return !m_in; }
LR & operator>>(std::string &line);
private:
std::istream &m_in; // input stream
std::ifstream m_in_file; // input file (if specified)
};
LR::LR(const std::string &filename, ... other stuff) :
: m_in(m_in_file)
{
// .... other stuff
if(filename.size() > 0)
{
m_in_file.open(filename.c_str());
}
// .... other stuff
}
and the class that uses this:
class CR { // config reader
public:
// .... other stuff
void Load_Variable(const std::string §ion, value, etc...);
private:
LR m_reader;
};
void CR::Load_Variable(const std::string §ion, value, etc.) {
string line;
bool found = false;
while (m_reader >> line)
{
// .... check stuff, etc.
}
}
Debugging in Qt, while (m_reader >> line) calls the operator void *().
My questions:
Why use a member var reference to a std::istream like this?
What's the purpose of returning the address of member var &m_in when it's always valid because it's a member var (or is this not true?)
Would operator *() of m_reader ever return false? I've searched a bit online and not found any similar examples of this kind of use of operators on member var refs. I need to look next at what it does when the file open fails.
Possibly this code originally used heap pointer vars or some other approach for the m_in var and it was changed somewhere along the way to be a normal member var, with the operators then edited to this? I think the history is not easy to get.
Thanks for the help, stackoverflow is awesome.
The istream has a flag that indicates if an error has occurred and it overrides the ! operator for easy access. You'll often see it used like this:
myStream >> line;
if(!myStream)
cout<<"Error reading data"<<endl;
So you are not returning a reference, you are returning a Boolean flag. Think of the ! operator as isNoError() accessor.
Your class is doing the same thing, just passing through the result from the stream it wraps.
The * operator is probably there as backward compatibility measure. Probably the existing code base is expecting a pointer and this was added so that the existing code base works with the new implementation.
Related
This is a follow-on from this question.
That article should explain why I am using a quint16 to extract the variant type.
I have derived class MyVariant from QVariant and implemented the QDataStream read operator.
This allows constructs like:
MyVariant vt;
str >> vt;
This is the streaming implementation:
QDataStream& operator>>(QDataStream& str, MyVariant& vt)
{
vt.clear();
quint16 type;
str >> type;
const QMetaType vtype(type);
if (vtype.isValid()) {
vt.create(type, nullptr);
if (!QMetaType::load(str, type, const_cast<void *>(vt.constData()))) {
Q_ASSERT_X(false, "MyVariant", qPrintable(QString("Cannot load type %u").arg(type)));
str.setStatus(QDataStream::ReadCorruptData);
}
}
else {
Q_ASSERT_X(false, "MyVariant", qPrintable(QString("Type %1 is not supported").arg(type)));
}
return str;
}
When the stream comes across a QColor (67), this code fails to create a valid QMetaType for it. QMetaType::isValid() returns false.
What could I possibly have forgotten to do?
Not sure if it matters, but I have added QT += gui to my .pro file.
Edit
I have added...
int type = qRegisterMetaType<QColor>("QColor");
... to my main function.
It returns 67, yet when I hit my streaming function the QMetaType creation still fails.
Okay, I solved this one by pure luck.
In my main, I register the type using...
qRegisterMetaTypeStreamOperators<QColor>("QColor");
And now it works!
Let me know in the comments if I did the right thing or not.
I have a routine that does some moderately expensive operations, and the client could consume the result as either a string, integer, or a number of other data types. I have a public data type that is a wrapper around an internal data type. My public class looks something like this:
class Result {
public:
static Result compute(/* args */) {
Result result;
result.fData = new ExpensiveInternalObject(/* args */);
return result;
}
// ... constructors, destructor, assignment operators ...
std::string toString() const { return fData->toString(); }
int32_t toInteger() const { return fData->toInteger(); }
double toDouble() const { return fData->toDouble(); }
private:
ExpensiveInternalObject* fData;
}
If you want the string, you can use it like this:
// Example A
std::string resultString = Result::compute(/*...*/).toString();
If you want more than one of the return types, you do it like this:
// Example B
Result result = Result::compute(/*...*/);
std::string resultString = result.toString();
int32_t resultInteger = result.toInteger();
Everything works.
However, I want to modify this class such that there is no need to allocate memory on the heap if the user needs only one of the result types. For example, I want Example A to essentially do the equivalent of,
auto result = ExpensiveInternalObject(/* args */);
std::string resultString = result.toString();
I've thought about structuring the code such that the args are saved into the instance of Result, make the ExpensiveInternalObject not be calculated until the terminal functions (toString/toInteger/toDouble), and overload the terminal functions with rvalue reference qualifiers, like this:
class Result {
// ...
std::string toString() const & {
if (fData == nullptr) {
const_cast<Result*>(this)->fData = new ExpensiveInternalObject(/*...*/);
}
return fData->toString();
}
std::string toString() && {
auto result = ExpensiveInternalObject(/*...*/);
return result.toString();
}
// ...
}
Although this avoids the heap allocation for the Example A call site, the problem with this approach is that you have to start thinking about thread safety issues. You'd probably want to make fData an std::atomic, which adds overhead to the Example B call site.
Another option would be to make two versions of compute() under different names, one for the Example A use case and one for the Example B use case, but this isn't very friendly to the user of the API, because now they have to study which version of the method to use, and they will get poor performance if they choose the wrong one.
I can't make ExpensiveInternalObject a value field inside Result (as opposed to a pointer) because doing so would require exposing too many internals in the public header file.
Is there a way to make the first function, compute(), know whether its return value is going to become an rvalue reference or whether it is going to become an lvalue, and have different behavior for each case?
You can achieve the syntax you asked for using a kind of proxy object.
Instead of a Result, Result::compute could return an object that represents a promise of a Result. This Promise object could have a conversion operator that implicitly converts to a Result so that "Example B" still works as before. But the promise could also have its own toString(), toInteger(), ... member functions for "Example A":
class Result {
public:
class Promise {
private:
// args
public:
std::string toString() const {
auto result = ExpensiveInternalObject(/* args */);
return result.toString();
}
operator Result() {
Result result;
result.fData = new ExpensiveInternalObject(/* args */);
return result;
}
};
// ...
};
Live demo.
This approach has its downsides though. For example, what if, instead you wrote:
auto result = Result::compute(/*...*/);
std::string resultString = result.toString();
int32_t resultInteger = result.toInteger();
result is now not of Result type but actually a Result::Promise and you end up computing ExpensiveInternalObject twice! You can at least make this to fail to compile by adding an rvalue reference qualifier to the toString(), toInteger(), ... member functions on Result::Promise but it is not ideal.
Considering you can't overload a function by its return type, and you wanted to avoid making two different versions of compute(), the only thing I can think of is setting a flag in the copy constructor of Result. This could work with your particular example, but not in general. For example, it won't work if you're taking a reference, which you can't disallow.
In my code, I want to identify some properties about the contents of a file, before deciding how to read the file. (That is, I search for a keyword, if found, it's going to be read with foo(std::ifstream&), else with bar(std::ifstream&)).
I implemented the method that searches for the keyword as
bool containsKeyword(std::ifstream& file, const char* keyword)
{
for ( std::string line; std::getline(file, line); )
{
if ( line == keyword )
{
return true;
}
}
return false;
}
This modifies the position of the file stream (either the end, if the keyword isn't found, or the position of the keyword). However I want that the position is reset after the search. This can be done with a ScopeGuard:
class FilePositionScopeGuard
{
private:
std::ifstream& file;
using FilePosition = decltype(std::declval<std::ifstream>().tellg());
FilePosition initial_position;
public:
FilePositionScopeGuard(std::ifstream& file_)
:
file(file_),
initial_position(file.tellg())
{
}
~FilePositionScopeGuard()
{
file.clear();
file.seekg(initial_position);
}
};
Now we add this to the method:
bool containsKeyword(std::ifstream& file, const char* keyword)
{
FilePositionScopeGuard guard(file);
for ( std::string line; std::getline(file, line); )
{
...
That's nice, because with exactly one additional line in the method, we get the behaviour of not modifying the std::ifstream no matter how the method is exited (one of the returns or an exception).
However, the method bool containsKeyword(std::ifstream&, const char*); does not express the constness. How can I adjust my method to express (at the level of the interface) that the method will not alter the current state?
You could change the signature to take a position-guarded file:
bool containsKeyword(const FilePositionScopeGuard &, const char *);
This allows the caller to pass an ifstream per the current signature (constructing a temporary guard for that operation), or to make their own guard and use it for several operations.
You'll need to make the ifstream member publicly accessible.
Do it with the text comment // the method does read from file but resets the read pointer.
Do not expect a user of the API to be a monkey at keyboard. Specifically don't mark ifstream argument as const while casting constancy out inside the method. It does make difference in a multithreaded program.
For example
bool read(Input &input);
Input input; //error
bool success = read(input);
will be an error because Input has no default constructor.
Is there any trickery I can use to get the Input object out of the function in this case? I imagine there must be some unique_ptr trickery available to me, but I'm not sure exactly how. Feel free to suggest other methods.
Please suggest with example how the read function could look.
I would rather not create a (meaningless) default constructor for Input just for this purpose, and note that this is just a silly example, so don't attach any special meaning to the words "Input", "read", etc. :)
bool read(unique_ptr<Input> &input) // read asume input is disposable/empty
{ ....
input.reset(new Input( a,d,c ) );
....
}
....
unique_ptr<Input> input; //error ?
bool success = read(input);
if (input)
if (succes)
input->X();
else
input->Y();
unique_ptr<Input> input_ptr = read();
where read() is defined as:
unique_ptr<Input> read()
{
.
.
.
return unique_ptr<Input>(new Input(x,y,z));
}
From the comments, it appears that your problem is to design a function that
can fail (and if so should signal that to caller),
but if not, produces a value of a type without a default cconstructor
The first point is easy: use exceptions.
The second point is also easy: use the function return value feature.
I.e.,
Object foo()
{
if( "didna wrok" )
{
throw std::runtime_error( "foo: I failed, miserably" );
}
return Object( arg1, arg2, arg3 );
}
Now there also many other ways to do this, but the above is the most natural, directly using the language features that are intended to support and fully solve these aspects.
If you are in pre-C+11 world, there is a workaround by use of malloc:
bool read(Input &input); // keep the function read intact
Input* input = static_cast<Input*>(malloc(sizeof(Input))); // bypass constructor
bool success = read(*input);
...
free(input); // don't forget to free input later
I have a URL class that overloads the ==, <, >, and != operators for simple comparison. The URL class has a string data member and some functions to act on the string. The operators work fine when tested with the URL class.
I also have a Page class that has a URL data member. I am trying to overload the same operators in the Page class. Equality in the Page class is based on equality of their respective URLs, so I use the URL class boolean operators in comparing pages. This creates some compiler errors that I cannot figure out. Code for URL operators:
bool URL::operator ==(URL & u) const {
//url is the string instance variable
return url == u.GetURL();
}
Code for Page operators:
bool Page::operator ==(Page & p) const {
//url is the URL instance variable of the Page class
return url == p.GetURL();
}
This produces errors like so:
src/Page.cpp: In member function ‘bool Page::operator==(Page&) const’:
src/Page.cpp:21: error: no match for ‘operator==’ in ‘((const Page*)this)->Page::url == Page::GetURL()()’
inc/URL.h:118: note: candidates are: bool URL::operator==(URL&) const
I predict that it is something dumb that I am forgetting. Will you prove me right?
edit: Const correctness has bitten me in the bum. Thanks for the help.
It should have been:
bool URL::operator ==(const URL & u) const {
//url is the string instance variable
return url == u.GetURL();
}
And analogously for the other operators.
If you still get compiler errors, perhaps you haven't made GetURL() const as well:
std:string URL::GetURL() const {
// whatever...
}
I would also like to point out that methods (ie the public interface) are there to protect external entities from changes in the implementation details. Also that a class is automatically a friend of itself (for the same reason) and thus just accessing the members of the other object is OK.
bool URL::operator ==(URL & u) const {
//url is the string instance variable
return url == u.GetURL();
}
Can be written like:
bool URL::operator ==(URL & rhs) const
{
return url == rhs.url; // No need to use GetURL()
}
In my mind this makes the code clearer (but this again is an opinion your tastes may vary)