在 VS2015 中访问类成员时出现运行时错误,但在 Linux 上没有

Posted

技术标签:

【中文标题】在 VS2015 中访问类成员时出现运行时错误,但在 Linux 上没有【英文标题】:Runtime error when accessing class member in VS2015 but not on Linux 【发布时间】:2017-08-09 08:13:20 【问题描述】:

此代码在 Linux 上使用 g++ 编译时可以正常工作,但是当我尝试在 VS 2015(调试和发布)中执行它们时,我收到运行时错误。它出什么问题了?

#include "stdafx.h"
#include <string.h>
#include <iostream>
using namespace std;

struct Stru1

  int   mem;
;

struct Stru2 : public Stru1

  char         szMem1[256];
  int               dwMem2;
  int               dwMem3;
;

static void clFun(Stru1* s) 

  Stru2* s2 = (Stru2*)s;
  cout << s2->szMem1 << endl;//blahblah
  cout << s2->dwMem2 << endl;//runtime error



class Temp 
 public:

  void callDispatch() 

      simRecv->mem = 2;

      Stru2* sro = (Stru2*)simRecv;
      strcpy(sro->szMem1, "blahblah");
      sro->dwMem2 = 11;
      sro->dwMem3 = 77;

      //cout << sro->szMem1 << endl;//blahblah
      //cout << sro->dwMem2 << endl;//runtime error when uncommented


      clFun(simRecv);
  

  ~Temp()  delete simRecv; 

  Stru1* simRecv = new Stru1;

;



int main()


  Temp tmp;
  tmp.callDispatch();


  return 0;

错误: 在 ConsoleApplication1.exe 中的 0x0000000077A0F23C (ntdll.dll) 处引发异常:0xC0000005:访问冲突读取位置 0x00000FB00188C508。

【问题讨论】:

因此您为Stru1 分配内存,将其转换为具有不同成员的Stru2*,并期望一切正常。? 您已经分配了 sinRecv = Stru1(带有“new Stru1”),然后将指针转换为 Stru2。 “新”分配的 sizeof(Stru1),因此尝试取消指向 Stru2 的指针会超出分配的末尾。 Stru2* sro = (Stru2*)simRecv; -- 从这行代码中删除强制转换。现在仔细阅读the error you get from your compiler。同样的事情here。错误说明了什么?那么你听过你的编译器吗?不,您继续并应用了强制转换来“关闭编译器”。 【参考方案1】:
Stru2* sro = (Stru2*)simRecv;

simRecvStru1,因此您对 Stru2 的不安全强制转换在此行中无效。

在这一行中你创建了这个Stru1

 Stru1* simRecv = new Stru1;

这里为 Stru1 分配了创建 Stru1 所需的内存,该内存小于 Stru2

通过这样做:

Stru2* sro = (Stru2*)simRecv;

你只是说:我有这个“东西”并将其视为Stru2。但是没有在任何地方创建new Stru2,所以该对象不存在。

和说的基本一样

我有一堵大墙,但我会把它当作房子,并期望里面有一扇门。

可能在不同平台上工作的原因可能是由于平台的内存分配不同。

至于类比:你可能已经到了墙的尽头,因此不会伤到你的头,但你不在房子里,你不会把钱包放在那里。

例如,这条线最终会指向某个地方:

sro->dwMem3 = 77; 

问题是:这是否在有效的程序空间内?如果是,则不会发生错误,但这并不意味着它是好的。您可能正在其他地方更改变量,从而导致不可预测的结果。

一个例子:

平台1:

| Stru1           |   some variable   |  some other variable         | 
| mem             |   0               |  11                          |
|                 |                   |  ((Stru2*) simRecv)->dwMem2  |
//no errors, but strange side effects

平台2:

| Stru1           |   some variable   |  some other program space    | 
| mem             |   0               |  ERROR: ACCES VIOLATION      |
|                 |                   |  ((Stru2*) simRecv)->dwMem2  |
//0xC0000005

如果您首先分配Stru2(通过实际创建它),一切都会好起来的:

Stru1* simRecv = (Stru1*) new Stru2;

话虽如此;这些演员表被认为是不安全的(出于现在显而易见的原因)。 另一种方法是使用,例如static_cast。它将确保您在尝试执行“非法”操作时会收到构建错误。

http://www.cplusplus.com/doc/tutorial/typecasting/

关于 cplusplus 的附加说明请参阅:What's wrong with cplusplus.com?

【讨论】:

以上是关于在 VS2015 中访问类成员时出现运行时错误,但在 Linux 上没有的主要内容,如果未能解决你的问题,请参考以下文章

创建新项目时出现 vs2015 ctp6 错误

访问向量类成员时出现分段错误

在 VS 2015 和 VS 2013 上运行同一段代码时出现问题

从逆序 C++ 访问向量时出现运行时错误 [关闭]

在 vs2017 中运行自定义工具时出现 T4 错误

在 VS2015 中构建会出现 SideBySide 错误