C
Christopher
I tryed an example of how to do streams "the right way" based on an example
from the book "Standard C++ IOStreams and Locals" by Langer and Kreft. My
example doesn't seem to handle errors correctly. I am unsure if the problem
is arising from the << and >> operators for my user defined type, or the
handling of std::cin itself. If I uncomment the ignore statement,
std::cin:
perator >> never seems to return. Otherwise it just goes into an
infinite loop. Any advise?
source:
/**
* This program demonstrates the _proper_ way to provide insterters and
* extractors for a user defined type, based on the book
* "Standard C++ IOStreams and Locales" by Langer and Kreft
*
* @author Christopher Pisz
*/
#include <ctime>
#include <locale>
#include <limits>
#include <iostream>
//------------------------------------------------------------------------------
/**
* A very simplified date class
*
* Intended to demonstrate proper insertion and extraction operators for user
* defined types
*/
class Date
{
public:
Date(int day, int month, int year)
{
m_date.tm_mday = day;
m_date.tm_mon = month - 1;
m_date.tm_year = year - 1900;
}
private:
template<class charT, class Traits>
friend std::basic_istream<charT, Traits> &
operator >>(std::basic_istream<charT, Traits> & is, Date & date);
template<class charT, class Traits>
friend std::basic_ostream<charT, Traits> &
operator <<(std::basic_ostream<charT, Traits> & os, const Date &
date);
/** Structure from standard <ctime> header which contains date data */
tm m_date;
};
//------------------------------------------------------------------------------
/**
* The insertion and extraction methods for the Date class
*
* NOTE - Using basic_istream and basic_ostream opposed to the commonly
misused
* istream or ostream allows for differant char types and traits to be
* supported along with facets using those template arguments
*
* NOTE - You will not see the already built in << or >> operations being
* performed for each primitive data member, because it is inefficient
* in that it would call flush() and attempt to synchronize cin and
cout
* each time they were used
*
* TODO - The insertion and extraction methods should also check the
exception
* mask of the stream and check for and rethrow the approproate
* exceptions
*
* TODO - Stream prefix and suffix operations were also discussed but skipped
in
* this implementation
*/
template<class charT, class Traits>
std::basic_istream<charT, Traits> & operator >>(std::basic_istream<charT,
Traits> & is, Date & date)
{
// Check if the stream is in a bad state
if( !is.good() )
{
return is;
}
// Use the time_get facet, which provides parsing and formatting
/** Used to get error state from the call to the time_get facet */
std::ios_base::iostate err = std::ios_base::goodbit;
std::use_facet<std::time_get<charT, std::istreambuf_iterator<charT,
Traits> > >
(is.getloc()).get_date(is, std::istreambuf_iterator<charT,Traits>(),
is, err, &date.m_date);
// Set the stream state to the state of the facet to inidicate any errors
is.setstate(err);
return is;
}
template<class charT, class Traits>
std::basic_ostream<charT, Traits> & operator <<(std::basic_ostream<charT,
Traits> & os, const Date & date)
{
// Check if the stream is in a bad state
if( !os.good() )
{
return os;
}
// Use the time_put facet, which provides parsing and formatting
if( std::use_facet<std::time_put<charT, std:
streambuf_iterator<charT,
Traits> > >
(os.getloc()).put(os, os, os.fill(), &date.m_date, 'x').failed() )
{
// Unrecoverable error
//
// Note - It could not have been formatting error, since a valid Date
// object was passed in as a parameter
os.setstate(std::ios_base::badbit);
}
return os;
}
//------------------------------------------------------------------------------
int main()
{
Date date(07, 07, 1976);
std::cout << "Enter your birthdate (<day> <month> <4 digit year>): ";
while( std::cin >> date, !std::cin.good() )
{
// Check if there was a fatal error
if( std::cin.bad() )
{
std::cout << "\nFatal Error, aborting...\n" << std::endl;
system("pause");
return 1;
}
// Otherwise, there was a recoverable error
// Either std::ios_base::failbit or std::ios_base::eofbit was set
std::cout << "\nError getting input. Try format of: \n"
<< "<2 digit day> <2 digit month> <4 digit year>\n"
<< std::endl;
// Reset error bits
std::cin.clear();
/* Infinite loop detectable here */
/* If I uncomment this then the getting of input never stops when
enter is hit
*
// Empty any left over characters from the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
*/
}
// Successfully got input
std::cout << "\nYou said you were born: "
<< date << "\n" << std::endl;
system("pause");
return 0;
}
from the book "Standard C++ IOStreams and Locals" by Langer and Kreft. My
example doesn't seem to handle errors correctly. I am unsure if the problem
is arising from the << and >> operators for my user defined type, or the
handling of std::cin itself. If I uncomment the ignore statement,
std::cin:
infinite loop. Any advise?
source:
/**
* This program demonstrates the _proper_ way to provide insterters and
* extractors for a user defined type, based on the book
* "Standard C++ IOStreams and Locales" by Langer and Kreft
*
* @author Christopher Pisz
*/
#include <ctime>
#include <locale>
#include <limits>
#include <iostream>
//------------------------------------------------------------------------------
/**
* A very simplified date class
*
* Intended to demonstrate proper insertion and extraction operators for user
* defined types
*/
class Date
{
public:
Date(int day, int month, int year)
{
m_date.tm_mday = day;
m_date.tm_mon = month - 1;
m_date.tm_year = year - 1900;
}
private:
template<class charT, class Traits>
friend std::basic_istream<charT, Traits> &
operator >>(std::basic_istream<charT, Traits> & is, Date & date);
template<class charT, class Traits>
friend std::basic_ostream<charT, Traits> &
operator <<(std::basic_ostream<charT, Traits> & os, const Date &
date);
/** Structure from standard <ctime> header which contains date data */
tm m_date;
};
//------------------------------------------------------------------------------
/**
* The insertion and extraction methods for the Date class
*
* NOTE - Using basic_istream and basic_ostream opposed to the commonly
misused
* istream or ostream allows for differant char types and traits to be
* supported along with facets using those template arguments
*
* NOTE - You will not see the already built in << or >> operations being
* performed for each primitive data member, because it is inefficient
* in that it would call flush() and attempt to synchronize cin and
cout
* each time they were used
*
* TODO - The insertion and extraction methods should also check the
exception
* mask of the stream and check for and rethrow the approproate
* exceptions
*
* TODO - Stream prefix and suffix operations were also discussed but skipped
in
* this implementation
*/
template<class charT, class Traits>
std::basic_istream<charT, Traits> & operator >>(std::basic_istream<charT,
Traits> & is, Date & date)
{
// Check if the stream is in a bad state
if( !is.good() )
{
return is;
}
// Use the time_get facet, which provides parsing and formatting
/** Used to get error state from the call to the time_get facet */
std::ios_base::iostate err = std::ios_base::goodbit;
std::use_facet<std::time_get<charT, std::istreambuf_iterator<charT,
Traits> > >
(is.getloc()).get_date(is, std::istreambuf_iterator<charT,Traits>(),
is, err, &date.m_date);
// Set the stream state to the state of the facet to inidicate any errors
is.setstate(err);
return is;
}
template<class charT, class Traits>
std::basic_ostream<charT, Traits> & operator <<(std::basic_ostream<charT,
Traits> & os, const Date & date)
{
// Check if the stream is in a bad state
if( !os.good() )
{
return os;
}
// Use the time_put facet, which provides parsing and formatting
if( std::use_facet<std::time_put<charT, std:
Traits> > >
(os.getloc()).put(os, os, os.fill(), &date.m_date, 'x').failed() )
{
// Unrecoverable error
//
// Note - It could not have been formatting error, since a valid Date
// object was passed in as a parameter
os.setstate(std::ios_base::badbit);
}
return os;
}
//------------------------------------------------------------------------------
int main()
{
Date date(07, 07, 1976);
std::cout << "Enter your birthdate (<day> <month> <4 digit year>): ";
while( std::cin >> date, !std::cin.good() )
{
// Check if there was a fatal error
if( std::cin.bad() )
{
std::cout << "\nFatal Error, aborting...\n" << std::endl;
system("pause");
return 1;
}
// Otherwise, there was a recoverable error
// Either std::ios_base::failbit or std::ios_base::eofbit was set
std::cout << "\nError getting input. Try format of: \n"
<< "<2 digit day> <2 digit month> <4 digit year>\n"
<< std::endl;
// Reset error bits
std::cin.clear();
/* Infinite loop detectable here */
/* If I uncomment this then the getting of input never stops when
enter is hit
*
// Empty any left over characters from the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
*/
}
// Successfully got input
std::cout << "\nYou said you were born: "
<< date << "\n" << std::endl;
system("pause");
return 0;
}