7

Here is a sample code:

#include <iostream>
#include <stdexcept>
#include <cstring>
#include <ctime>
#include <sstream>

using std::cout;
using std::endl;

std::size_t const BUF_SIZE(1000);

std::ostream& operator<<(std::ostream& os, std::tm const& rhs)
{   
    os << asctime(&rhs);
    return os; 
}   

std::istream& operator>>(std::istream& is, std::tm& rhs)
{   
    while (is.peek() == ' ' || is.peek() == '\t')
    {   
        is.get();
    }   
    std::streampos curPos = is.tellg();
    char buf[BUF_SIZE];
    is.getline(buf, BUF_SIZE);
    char* ptr = strptime(buf, "%D %T", &rhs);
    if (ptr == 0)
    {   
        throw std::runtime_error("strptime() failed!");
    }   
    std::size_t processed = ptr - buf;
    is.seekg(curPos + static_cast<std::streampos>(processed));
    return is; 
}   

int main()
{   
    std::istringstream is("10101 07/09/12 07:30:00 123.24");
    int uuid(0);
    double price(0);
    std::tm ptime; std::memset(&ptime, 0, sizeof(tm));

    is >> uuid >> ptime >> price;
    cout << "UUID: " << uuid << endl;
    cout << "Time: " << ptime;
    cout << "Price: " << price << endl;
} 

where I'm trying to overload the << and >> operators for struct tm! If I compile my code with g++ and run it, I get:

UUID: 10101
Time: Sun Jul  9 07:30:00 2012
Price: 123.24

Perfect!

But, if I compile it using clang++, I get:

UUID: 10101
Time: Sun Jul  9 07:30:00 2012
Price: 0

OOPS!

What is going on? it this an issue with clang or it's the way i'm processing the istream?

Reza Toghraee
  • 1,603
  • 1
  • 14
  • 21
  • At ideone.com [gcc-4.3.4](http://ideone.com/UDQEm) and [gcc-4.5.1](http://ideone.com/NXZqK) produce the same output you see with clang. – Blastfurnace Jun 12 '12 at 01:36
  • Does `strptime` work as-is on clang for you? It is a non-standard (POSIX) function and I'm not sure if clang's libc++ supports it. – dirkgently Jun 12 '12 at 01:39
  • `gcc 4.6.3-1ubuntu5` gives the _Perfect!_ output Reza reports on my x86-64 Ubuntu system. – sarnold Jun 12 '12 at 01:39
  • Is it that `std::memset(&ptime, 0, sizeof(tm));` is overwriting something critical, especially if `std::tm` has a default constructor, etc. – Ken Y-N Jun 12 '12 at 01:43
  • I get the correct output using both `g++` (version 4.7) and `clang++` (version 3.0). – Keith Thompson Jun 12 '12 at 01:52
  • 1
    I hope you're running more than one test. – Captain Obvlious Jun 12 '12 at 02:01
  • 1
    I tested it with gcc-4.2 and gives me the same output as clang does. gcc-4.8 is the one that gave me the 'perfect' answer. However the is.clear() per Cubbi's answer seems to make it work! – Reza Toghraee Jun 12 '12 at 12:42

1 Answers1

9

I was able to reproduce this (g++ 4.7.0 and clang++ 3.1 with libc++-svn) and a brief debugging session showed that clang++ sets the eofbit after getline (which is normal), which then somehow causes seekg to set failbit. This sounds like a bug, given that seekg first clears eofbit (§27.7.2.3/41)

To work around, insert is.clear() anywhere between the getline and the seekg.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • 2
    PS: this wording is new in C++11, C++03 didn't say that and in fact made it doubtful that we can seek away from eof: [LWG issue 342](http://cplusplus.github.com/LWG/lwg-closed.html#342) – Cubbi Jun 12 '12 at 04:01