27

I have a little piece of code in C++:

#include <iostream>
#include <iterator>
#include <string>

using namespace std;

int main() {

    int i=0;
    istream_iterator<string> EOS;
    double x;

    return 0;
}

Now i compile it with my g++ (GCC) 4.4.4

g++ -W -Wall -pedantic test.cc -o test

And get:

test.cc: In function 'int main()':
test.cc:9: warning: unused variable 'i'
test.cc:11: warning: unused variable 'x'

Why there is no warning for unused EOS?

Kylo
  • 2,300
  • 1
  • 19
  • 24
  • FACT: `EOS` **is not** `lock_guard` or any kind of variable to be used with the sole purpose of the effect of its destructor, and this is what happens most of the time, with `std::string`, etc. So, there indeed should have been a warning there, so that the user notice that it can eliminate the variable, in this sense, what's the big difference between unused `std::string` vs unused `int` at a high level? None. This is a design issue in C++. – oblitum Jul 15 '16 at 20:33
  • 2
    @pepper_chico the compiler has to get *very* clever to deduce that whilst `~istream_iterator()` is not trivial, eliding *both* `istream_iterator()` *and* `~istream_iterator()` has the same result as leaving them in. In the general case, such cleverness is **impossible**, so there has to be a point where the analysis stops early – Caleth Apr 23 '18 at 12:24
  • @Caleth those are the implementation details. I was pointing at the language issue at a high level, where you want a simple response, when you look at the code, for the question: "is this not explicitly used by the programmer?". You can answer it, but a C++ compiler can't, since it only sees "use" as defined by the language, which considers destructors, which is irrelevant for the question posed. – oblitum Apr 26 '18 at 03:16

3 Answers3

38

It is not a primitive value, so its constructor and/or destructor might have desired side effects.

To illustrate that this happens in practice: I use a class to time sections of code, that looks roughly like this:

class Timed {
    double start;
    public:
        Timed() { start = now(); }
        ~Timed() { std::cout << (now() - start) << '\n'; }
}

So to measure how long a function takes, I simply do:

void slow() {
    Timed t;
    // heavy operation here...
}

The variable t never gets used, but it's still important to the behaviour of the code.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • 3
    +1 For using destructor to calculate the end of timing. Cool trick. – Thomas Matthews Mar 14 '11 at 22:30
  • 1
    It's called RIAA and has been a design goal since inception of C++ (see Bjarne Stroustrup) – sehe Mar 15 '11 at 11:59
  • 5
    @sehe You probably ment RAII :-) didn't you? – Kylo Mar 21 '11 at 10:52
  • @Kylo: Yup - sry. Should've looked that up – sehe Mar 21 '11 at 20:08
  • This reminds me of performance tracking :) https://github.com/easylogging/easyloggingpp#performance-tracking that uses same mechanism to track performance of function / blocks (Disclaimer: I am developer of this lib) -- woops just noticed this thread is pretty old :) Long live SO – abumusamq Jan 10 '14 at 03:56
7

istream_iterator<string> has a constructor, so the declaration of EOS isn't really a no-op like the declarations of i and x are.

Often you want to declare a class-type object and then not do anything with it. For example, consider std::lock_guard in C++0x (boost::scoped_lock in Boost) or any other kind of scope guard class. You don't usually want to do anything with that kind of object, you just want to create the object so that its destructor get run at the end of the block to perform whatever cleanup needs to be performed.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
4

Because you could have done that with a purpose. It's not a primitive. Maybe the constructor and destructor do something important?

MFC even had classes that operated that way, you could do this:

void foo()
{
    CWaitCursor cursor;

    [...]
}

That would display an hourglass icon for the duration of the function.

EboMike
  • 76,846
  • 14
  • 164
  • 167