草庐IT

c++ - CString 运算符 "+="和 "+"之间的不同行为

coder 2024-02-03 原文

在将应用程序从 VisualStudio 2005 迁移到 VisualStudio 2015 时,我们发现在某些代码中存在不同的行为,当该代码是使用 VS2015 构建时连接 CString 实例。
因此,我创建了一个简单的 Win32 控制台应用程序来演示该问题。

控制台应用程序(使用 MFC 作为共享 dll 和 Unicode 字符集)执行这个简单的功能:

void f()
{
   CString x( '\0' );

   CString r( 'a' );
   r += x;
   CString rr( 'a' );
   rr = rr + x;

   int rSize = r.GetLength();
   int rrSize = rr.GetLength();

   assert( rSize == rrSize ); // This assert fires when compiled and run 
                              // under Visual Studio 2015!
}

它表明,当一个包含 '\0' 字符的 CString 连接到另一个 CString 实例时,使用 '+=' 或使用 '+' 会导致不同的结果!

当使用“+=”时,计算结果的大小会计算所有字符直到第一个“\0”...因此最终大小为 1!
相反,当使用运算符“+”时,结果 CString 大小为 2,即串联实例大小的总和!

在 VisualStudio 2005 中,结果大小始终是串联实例大小的总和!

filed a bug几周前给微软,但直到现在我还没有得到那些人的答复。

我的问题:
1. 有人在 MCF 库中发现了这个错误吗??
2. 你是如何解决这个错误的?我们正在考虑禁止使用 += 运算符,或者用自定义类替换 CString 类,但所有这些在我看来“有点”侵入性。

最佳答案

CStringT Class 的文档包含以下神秘声明:

Although it is possible to create CStringT instances that contain embedded null characters, we recommend against it. Calling methods and operators on CStringT objects that contain embedded null characters can produce unintended results.

坦率地说,我真的不知道最后一句话是什么意思。我将其视为在嵌入空字符时要小心的警告。无论如何,这样做时契约(Contract)保证仍然有效。

分析:

CStringT::operator+= 显然不是这种情况。 , 尽管。在问题的示例代码中,operator+= 的实现调用了

CSimpleStringT& operator+=( const CSimpleStringT& strSrc )

重载,通过调用修改当前实例

void Append( const CSimpleStringT& strSrc )

依次调用

void Append( PCXSTR pszSrc, int nLength )

传递一个明确的长度参数。这应该足以处理带有嵌入空字符的 C 风格字符串。奇怪的是,该实现随后开始通过调用 StringLengthN(pszSrc, nLength)(实现为对 wcsnlen 的调用)来重新猜测输入,以重新计算 pszSrc 的长度。这将为示例代码中的 CStringT 实例 x 返回 0。

结果:

对我来说,这似乎是实现中的一个错误。顺便说一句,如果您将参数反转为 operator+=(即 x += r;r += x;),结果是正如预期的那样,长度为 2 的字符串。

解决方案:

唯一干净的解决方案是让 Microsoft 确认该错误,并提供修复程序。不过,我不会屏住呼吸,因为如果错误修复改变了已交付产品的行为,Microsoft 通常不会提供错误修复。

如果您无法说服 Microsoft 修复该错误,您唯一的选择就是不使用具有不良行为的运算符。一种方法是使用另一个字符串类。一个完善的替代品是 std::wstring ,您可以在必要时将其转换为 CStringW (CStringW cstr(s.c_str(), s.length());)。


更新(2016-09-13):

OP 提交了一份 defect report与微软合作,他们承认了这个错误。已实现错误修复,但 “它不会出现,直到库的下一个主要版本(可能不一定在当前 [2016-03-31] Visual Studio vNext 中发布)”

关于c++ - CString 运算符 "+="和 "+"之间的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35044248/

有关c++ - CString 运算符 "+="和 "+"之间的不同行为的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  8. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  9. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  10. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

随机推荐