【问题标题】:Convert C++Builder AnsiString to std::string via boost::lexical_cast通过 boost::lexical_cast 将 C++Builder AnsiString 转换为 std::string
【发布时间】:2009-05-22 14:40:44
【问题描述】:

对于学校作业,我必须使用 Borland C++ Builder 用 C++ 实现一个项目。

由于 VCL 对所有 GUI 组件使用 AnsiString,我必须将所有 std::strings 转换为 AnsiString 以便显示。

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

当然可以,但是我想避免编写和代码重复有点乏味。当我们在其他上下文中使用 Boost 时,我决定提供一些帮助函数 go get boost::lexical_cast 来使用 AnsiString。到目前为止,这是我的实现:

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;
}

一开始我在访问冲突之后遇到访问冲突,但自从我添加了 .exceptions() 东西后,图片变得更清晰了。 执行转换时,我得到以下异常:

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

有没有人知道如何修复它并可以解释为什么会发生错误?我的 C++ 经验非常有限。

反过来的转换例程是:

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

也许有人也会在这里发现错误:)

致以最诚挚的问候!

编辑:

目前我正在使用 Jem 的编辑版本,它在一开始就可以工作。在使用该程序一段时间后,Borland Codeguard 在已经释放的区域中提到了一些指针算法。有什么想法可以与之相关吗?

Codeguard 日志(我使用的是德文版本,译文标有星号):

------------------------------------------
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 是带有已发布运算符的文件,第 31 行是:

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

感谢您的帮助:)

【问题讨论】:

  • 可能是一个错字,但不要忘记 std::ostream & 运算符中的 &
  • 根据cppreference.com/wiki/io/exceptions,当我省略 .exceptions() 调用时,该错误被忽略。因此,当我立即处理结果而不进行处理时,会导致访问冲突。到目前为止,这至少是我的解释。
  • IMO 您现在遇到的“已释放区域”问题不是由您使用流和字符串引起的,而更有可能是您创建/删除它们的方式。您在某处使用新/删除吗?如果您发布重现问题的最小代码,则应该不难发现它。
  • 通过非常量引用传递AnsiString 似乎会导致奇怪的、难以重现的崩溃。他们使用写时复制语义,也许编译器会搞砸与此相关的东西。

标签: c++ boost c++builder lexical-cast


【解决方案1】:

仍未使用 boost,但可能是解决您当前问题的第一步。你可以试试这个:

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;
}

编辑:更完整的解决方案,考虑到 op 的 cmets:

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; 
} 

但是,对于 std::string 和 AnsiString 具有不同的 operator >> 行为可能可以满足您的需求,但总的来说不是很好。你仍然可以给它一个明确的名字。

【讨论】:

  • 我认为只会复制一个单词
  • 是的,但这可能是预期的行为(或不是)。读取整个缓冲区可以在上层完成。我不知道流,但在这里甚至可以通过使用 stream.get() 来避免临时字符串
  • 前段时间我从 >> 切换到 getline() 因为我想读取整个字符串。所以阅读整个字符串是我想要的:)
  • 如果我把 istr.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit);调用您编辑的建议,它会因“ios_base::failbit set”而崩溃,奇怪:)
  • 我认为是正常的。当您读取流中的所有内容时,根据定义,您会到达它的末尾,并引发异常。如果您没有捕获它(使用 try / catch),它会导致您遇到的崩溃(未处理的异常错误?)。在我的示例中,您不应该设置异常位,或者捕获异常而只报告那些实际上是错误的。
【解决方案2】:

您的转换会转换输入的一行。如果有两行,那是一个严重的问题,如果没有,这是一个相当致命的错误。在这种情况下,最好的解决方案不是新的operator&gt;&gt;,而是模板特化。我的头顶:

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

(您不应该重载其他人的模板。在 std:: 中,这是非法的,在其他地方只是不好的做法)

【讨论】:

  • @James:你当然可以特化模板函数——它们不能只进行部分特化。
【解决方案3】:

你也可以试试这个!我在使用 hashlib++ 时也遇到了这种问题。

String toAnsiString(const std::string& myString)
{
  return String(myString.c_str());
}

【讨论】:

    【解决方案4】:

    除了 MSalters cmets,将 std::string 的实际长度也传递给 AnsiString 会更有效,这样它就不需要浪费 CPU 周期来手动计算长度:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-03
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-28
      相关资源
      最近更新 更多