【问题标题】:C++ Simple IF clause changes value of a static const char variableC++ 简单 IF 子句更改静态 const char 变量的值
【发布时间】:2015-12-11 12:45:12
【问题描述】:

好的,我已经处理了两天了,但我找不到解决方案。

问题:我正在尝试使用 Winapi 将过滤器设置为 文件选择对话框。我正在使用GetOpenFileName 函数来执行此操作。此函数使用 结构 来设置选项,例如文件扩展名过滤器。这个结构的成员lpstrFilter 需要一定的字符串格式。我完全按照 Winapi 的指示设置该字符串,但由于某种原因,该字符串的值发生了变化。

我有这个 static const char *

//This contains string "JPG"
static const char * extensionFilter = v->trabajo10.C_JMV_SelectFile_FileExtension7.GetString();

//This forms a filter string which applies to OPENFILENAME structure.
string sFilter;
sFilter.append("Format: ");
sFilter.append(extensionFilter);
sFilter.push_back('\0');
sFilter.append("*.");
sFilter.append(extensionFilter);
sFilter.push_back('\0');
const char * filter = sFilter.c_str();
ofn.lpstrFilter = filter; //This sets: --> Format: JPG\0*.JPG\0

//This opens the file selection dialog
if (GetOpenFileName(&ofn)==TRUE){
...

文件选择对话框看起来正确,如下所示:

笑话来了,我把代码修改成这样:

//This contains string "JPG"
static const char * extensionFilter = v->trabajo10.C_JMV_SelectFile_FileExtension7.GetString();

if(1){
   //This forms a filter string which applies to OPENFILENAME structure.
   string sFilter;
   sFilter.append("Format: ");
   sFilter.append(extensionFilter);
   sFilter.push_back('\0');
   sFilter.append("*.");
   sFilter.append(extensionFilter);
   sFilter.push_back('\0');
   const char * filter = sFilter.c_str();
   ofn.lpstrFilter = filter; //This sets: --> Format: JPG\0*.JPG\0
}

//This opens the file selection dialog
if (GetOpenFileName(&ofn)==TRUE){
...

这就是结果,问题

过滤器字符串被修改???

【问题讨论】:

  • 如果您在调用GetOpenFileName 之前使用了调试器并检查了OPENFILENAME 结构,您就不必问这个问题了。这个问题弥补了事实。
  • @IInspectable 我无法使用调试器,我使用的 IDE 不允许。
  • @ProtectedVoid 您使用哪个 IDE?并且您始终可以单独获得调试器; WinDbg 和 gdb 都可以独立于 IDE 运行。
  • @andlabs 我使用 CA Plex 6.1。这是一个相当古老的 IDE,可让您创建多平台应用程序。我别无选择,我必须使用这个 IDE。它甚至不允许您定义 C++ 函数。它迫使您像使用简单的脚本语言一样使用 C++ 进行编程。我希望你能多了解我的局限。
  • 这实际上不是if 子句。这是大括号{} 括号内的任何声明都属于不同的范围,它们不会在括号外看到。

标签: c++ winapi memory reference getopenfilename


【解决方案1】:
if(1){
   //This forms a filter string which applies to OPENFILENAME structure.
   string sFilter;
   sFilter.append("Format: ");
   sFilter.append(extensionFilter);
   sFilter.push_back('\0');
   sFilter.append("*.");
   sFilter.append(extensionFilter);
   sFilter.push_back('\0');
   const char * filter = sFilter.c_str();
   ofn.lpstrFilter = filter; //This sets: --> Format: JPG\0*.JPG\0
}

sFilter 变量的生命周期在它声明的块结束时结束。 sFilter.c_str() 返回的指针一直有效,直到 sFilter 被修改或销毁。

您在此指针失效后使用它。这与您昨天遇到的问题相同,我在 cmets 中对此问题进行了猜测。这就是为什么您需要展示完整的 MCVE。这个问题看起来也与您一周前提出的问题重复:Winapi GetOpenFileName Extension Filter not working。我建议您花一些时间来确保您完全理解c_str() 返回的值的有效性。

您必须确保sFilter 在您完成指针操作之前一直存在。在外部块中声明 sFilter 以确保这一点。

【讨论】:

  • 我现在明白这个问题了,谢谢。但这迫使我在外部块中创建一个变量,这意味着即使我不需要它也会被定义?如果我只在满足条件时使用它怎么办?满足条件时创建它不是合乎逻辑吗?再次感谢。
  • 是的,我明白你为什么这样写代码了。这是一个容易掉入的陷阱。
  • @ProtectedVoid 文本是有条件创建的,所以必须有条件地销毁。显然它必须在原始条件结束之后被销毁。所以原始条件之外的一些对象至少必须记住文本是否必须被销毁。在条件之外声明sFilter(但默认为空)是实现它的简单方法。
  • @JSF 您可以清除变量的内容,但声明了变量,如果不使用它会使您的代码效率低下。如果我声明了 100 个变量并且仅在满足条件时才使用它们,那么所有的内存分配都将毫无用处。我从 C++ 开始,我的目的是增加我的知识。谢谢。
  • 如果是 100 个条件变量,那么减少未使用案例的占用空间是值得的。在这里,足迹可以减少到一个 bool 告诉 ofn.lpstrFilter 是否“拥有”它所指向的东西。 bool 需要在条件 之外,条件内的代码需要不同,以便文本缓冲区归该指针所有。默认的空字符串成本非常低。因此,将“未使用”的占用空间减少到最少一个 bool 并不值得付出大量努力。
【解决方案2】:

问题是你有一个超出范围的变量

if(1){
   string sFilter;

   // ... code

   // Right here
   const char * filter = sFilter.c_str();      
   ofn.lpstrFilter = filter;
}

在该块结束后,filter 超出范围,因此ofn.lpstrFilter 有一个悬空指针。

【讨论】:

  • 实际上filter 超出范围没有区别。悬空指针是因为sFilter 超出范围。 (我相信您知道这一点,甚至引用了代码来说明这一点。但您不准确的描述可能会使某些人感到困惑。)将filter 移至更广泛的范围无济于事,也不会将其留在狭窄的范围内造成伤害。仅将 sFilter 移至更广泛的范围即可解决此问题。
【解决方案3】:

回答 ProtectedVoid 对声明未使用对象的担忧:假设std::string 是一个昂贵的对象,而且这种情况不太可能发生。除非条件为真,否则您不希望构造对象。但它必须持续超出条件的范围。所以我们使用默认构造的unique_ptr 比默认构造的string 便宜得多的事实:

std::unique_ptr<std::string> scope_extender;
if( something unlikely ){
       //This forms a filter string which applies to OPENFILENAME structure.
       std::string* sFilter = new std::string;
       scope_extender.reset( sFilter );
       sFilter->append("Format: ");
       sFilter->append(extensionFilter);
       sFilter->push_back('\0');
       sFilter->append("*.");
       sFilter->append(extensionFilter);
       sFilter->push_back('\0');
       const char * filter = sFilter->c_str();
       ofn.lpstrFilter = filter; //This sets: --> Format: JPG\0*.JPG\0
    }

显然,我不想暗示std::string 的构建成本足以值得所有这些麻烦。但是在类似情况下的某些对象可能是。此外,还有一条评论说,如果一个条件中有许多次要对象怎么办。在这种情况下,您可能需要一个实用结构来将它们保存在一起,并且 unique_ptr 有条件地拥有该结构。

【讨论】:

  • 谢谢,很好的例子!感谢您的努力。
猜你喜欢
  • 1970-01-01
  • 2015-07-24
  • 2020-08-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 2016-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多