2

For a school assignment I have to implement a project in C++ using Borland C++ Builder.

As the VCL uses AnsiString for all GUI Components I have to convert all of my std::strings to AnsiString for the sake of displaying.

std::string inp = "Hello world!";
AnsiString outp(inp.c_str());

works of course but is a bit tedious to write and code duplication I want to avoid. As we use Boost in other contexts I decided to provide some helper functions go get boost::lexical_cast to work with AnsiString. Here is my implementation so far:

std::istream& operator>>(std::istream& istr, AnsiString& str) {
    istr.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit);
    std::string s;
    std::getline(istr,s);
    str = AnsiString(s.c_str());
    return istr;
}

In the beginning I got Access Violation after Access Violation but since I added the .exceptions() stuff the picture gets clearer. When the conversion is performed I get the following Exception:

ios_base::eofbit set [Runtime Error/std::ios_base::failure]

Does anyone have an idea how to fix it and can explain why the error occurs? My C++ experience is very limited.

The conversion routine the other way round would be:

std::ostream& operator<<(std::ostream& ostr,const AnsiString& str) {
    ostr << (str.c_str());
    return ostr;
}

Maybe someone will spot an error here too :)

With best regards!

Edit:

At the moment I'm using the edited version of Jem, it works in the beginning. After a while of using the programm the Borland Codeguard mentions some pointer arithmetic in already freed regions. Any ideas how this could be related?

The Codeguard log (I'm using the german version, translations marked with stars):

------------------------------------------
Fehler 00080. 0x104230 (r) (Thread 0x07A4):
Zeigerarithmetik in freigegebenem Speicher: 0x0241A238-0x0241A258. **(pointer arithmetic in freed region)**
| d:\program files\borland\bds\4.0\include\dinkumware\sstream Zeile 126:
|               {   // not first growth, adjust pointers
|               _Seekhigh = _Seekhigh - _Mysb::eback() + _Ptr;
|>              _Mysb::setp(_Mysb::pbase() - _Mysb::eback() + _Ptr,
|                   _Mysb::pptr() - _Mysb::eback() + _Ptr, _Ptr + _Newsize);
|               if (_Mystate & _Noread)
Aufrufhierarchie: **(stack-trace)**
   0x00411731(=FOSChampion.exe:0x01:010731) d:\program files\borland\bds\4.0\include\dinkumware\sstream#126
   0x00411183(=FOSChampion.exe:0x01:010183) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#465
   0x0040933D(=FOSChampion.exe:0x01:00833D) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#151
   0x00405988(=FOSChampion.exe:0x01:004988) d:\program files\borland\bds\4.0\include\dinkumware\ostream#679
   0x00405759(=FOSChampion.exe:0x01:004759) D:\Projekte\Schule\foschamp\src\Server\Ansistringkonverter.h#31
   0x004080C9(=FOSChampion.exe:0x01:0070C9) D:\Projekte\Schule\foschamp\lib\boost_1_34_1\boost/lexical_cast.hpp#151

Objekt (0x0241A238) [Größe: 32 Byte] war erstellt mit new **(Object was created with new)**
| d:\program files\borland\bds\4.0\include\dinkumware\xmemory Zeile 28:
|   _Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)
|   {   // allocate storage for _Count elements of type _Ty
|>  return ((_Ty _FARQ *)::operator new(_Count * sizeof (_Ty)));
|   }
| 
Aufrufhierarchie: **(stack-trace)**
   0x0040ED90(=FOSChampion.exe:0x01:00DD90) d:\program files\borland\bds\4.0\include\dinkumware\xmemory#28
   0x0040E194(=FOSChampion.exe:0x01:00D194) d:\program files\borland\bds\4.0\include\dinkumware\xmemory#143
   0x004115CF(=FOSChampion.exe:0x01:0105CF) d:\program files\borland\bds\4.0\include\dinkumware\sstream#105
   0x00411183(=FOSChampion.exe:0x01:010183) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#465
   0x0040933D(=FOSChampion.exe:0x01:00833D) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#151
   0x00405988(=FOSChampion.exe:0x01:004988) d:\program files\borland\bds\4.0\include\dinkumware\ostream#679

Objekt (0x0241A238) war Gelöscht mit delete **(Object was deleted with delete)**
| d:\program files\borland\bds\4.0\include\dinkumware\xmemory Zeile 138:
|   void deallocate(pointer _Ptr, size_type)
|       {   // deallocate object at _Ptr, ignore size
|>      ::operator delete(_Ptr);
|       }
| 
Aufrufhierarchie: **(stack-trace)**
   0x004044C6(=FOSChampion.exe:0x01:0034C6) d:\program files\borland\bds\4.0\include\dinkumware\xmemory#138
   0x00411628(=FOSChampion.exe:0x01:010628) d:\program files\borland\bds\4.0\include\dinkumware\sstream#111
   0x00411183(=FOSChampion.exe:0x01:010183) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#465
   0x0040933D(=FOSChampion.exe:0x01:00833D) d:\program files\borland\bds\4.0\include\dinkumware\streambuf#151
   0x00405988(=FOSChampion.exe:0x01:004988) d:\program files\borland\bds\4.0\include\dinkumware\ostream#679
   0x00405759(=FOSChampion.exe:0x01:004759) D:\Projekte\Schule\foschamp\src\Server\Ansistringkonverter.h#31

------------------------------------------

Ansistringkonverter.h is the file with the posted operators and line 31 is:

std::ostream& operator<<(std::ostream& ostr,const AnsiString& str) {
    ostr << (str.c_str()); **(31)**
    return ostr;
}

Thanks for your help :)

Johan
  • 74,508
  • 24
  • 191
  • 319
leen
  • 8,568
  • 3
  • 23
  • 18
  • Probably a typo, but do not forget the & in std::ostream & operator < – Jem May 22 '09 at 14:57
  • According to http://www.cppreference.com/wiki/io/exceptions the error is ignored when I omit the .exceptions() call. So when I worked with the result straight away without handling this resulted in the access violations. This was at least my explanation so far. – leen May 22 '09 at 15:59
  • 1
    IMO the problem you now have with "freed region" is not caused by your usage of streams and strings, but more likely by the way you are creating / deleting them. Are you using new / delete somewhere ? If you post the smallest code which reproduce the issue, it should not be too difficult to spot it. – Jem May 23 '09 at 12:58
  • 1
    Passing `AnsiString` by non-const reference seems to lead to weird, hard-to-reproduce crashes. They use copy-on-write semantics, perhaps the compiler messes something up relating to that. – M.M Sep 03 '14 at 01:19

4 Answers4

2

Still not using boost, but may be a first step to solve your current problem. You may try this:

std::istream& operator>>(std::istream& istr, AnsiString& str) {
    istr.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit);
    std::string s;
    istr >> s;
    str = AnsiString(s.c_str());
    return istr;
}

EDIT: more complete solution, taking op's comments into account:

std::istream& operator>> (std::istream& istr, AnsiString& str) 
{ 
    std::string tmp;

    std::istreambuf_iterator<char> it(istr), end; 
    std::copy(it, end, std::inserter(tmp, tmp.begin())); 

    str = AnsiString(tmp.c_str());

    return istr; 
} 

However, having different operator >> behavior for std::string and AnsiString is probably ok for your needs, but not very nice in general. You can still give it an explicit name.

Jem
  • 2,255
  • 18
  • 25
  • I think that will only copy a single word – James Hopkin May 22 '09 at 15:04
  • Yes, but it may be the expected behaviour (or not). Reading the entire buffer could be done at an upper level. I do not know streams by heart, but it is probably possible here to even avoid the temporary string, by using stream.get() – Jem May 22 '09 at 15:15
  • I switched from >> to getline() some time ago because I want to read the entire string. So reading the whole string is what I want :) – leen May 22 '09 at 15:23
  • If I put the istr.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit); call into your edited suggestion it crashes with "ios_base::failbit set", strange :) – leen May 22 '09 at 19:32
  • I think that it is normal. As you read everything in the stream, by definition you reach the end of it, and an exception is thrown. If you do not catch it (using try / catch), it causes the crash you're experiencing (a unhandled exception error ?). With my example, you should either not set the exceptions bits, or catch exceptions but only report those which are actually errors. – Jem May 22 '09 at 21:32
1

You may also try this! I had also that kind of problem working with hashlib++.

String toAnsiString(const std::string& myString)
{
  return String(myString.c_str());
}
Suhrob Samiev
  • 1,528
  • 1
  • 25
  • 57
1

Your conversion converts one line of the input. That's a serious problem if there are two lines, and a rather fatal bug if there are none. The best solution in this case is not a new operator>>, but a template specialization. Top of my head:

template< > AnsiString lexical_cast<AnsiString, std::string>(std::string const& s)
{
    return AnsiString(s.c_str());
}

(You're not supposed to overload other peoples templates. In std::, it's illegal, elsewhere just bad practice)

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

In addition to MSalters comments, It would be more efficient to pass the std::string's actual length to AnsiString as well, so that it does not need waste CPU cycles to calculating the length manually:

template<> System::AnsiString lexical_cast<System::AnsiString, std::string>(std::string const& s)
{
    return System::AnsiString(s.c_str(), s.length());
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770