《从缺陷中学习C/C++》——6.4 临时对象的生存期

6.4 临时对象的生存期

从缺陷中学习C/C++
代码示例

class MyString {
  public:
  MyString(){
    s_ = (char *)malloc(strlen(str) + 1);
    strcpy(s_, str);
  }
  ~MyString() {
    printf("destory\n");
  }
  friend MyString operator+(const MyString &lstr, const MyString &rstr){
    size_t llen = strlen(lstr);
    size_t rlen = strlen(rstr);
    char buf[llen + rlen + 1];
    strcpy(buf, lstr);
    strcat(buf, rstr);
    return MyString(buf);
  }
  operator const char *() const { //当string转换char* 时调用
    return _s;
  }
  private:
    char *_s;
  };
  int main()
  {
    MyString s1("hello "), s2("world !");
    const char *p = s1 + s2;
    printf("%s\n", p);
    return 0;
}

现象&结果
程序运行时通常是正常的,但有时会出错,特别是在多线程时,会出现奇特的错误:例如,指针p指向的内容不是期望的内容。

Bug分析
错误出在main函数中的const char *p = s1 + s2代码行处。程序会首先生成一个临时对象,用来存储s1+s2的值,然后再把临时对象的值赋给p,随后该临时对象析构。所以,指针p指向了一块非法内存。因为临时对象已经被析构,所以这块非法内存被系统识别为“未使用”的状态,可以被再分配使用。如果在程序中没有其他操作读写这块内存时,其内容还没有被改变,所以,可能输出符合程序预期的正确结果。但是,没有任何方法阻止那块内容的改变。所以,如果有其他操作对这块内存单元进行写操作后,可能输出的是随机值。

正确代码
在main函数中显式给出临时对象:

int main()
{
    MyString s1("hello "), s2("world !");
    String temp = t1 + t2;
    const char *p = temp;
    printf("%s\n", p);
    return 0;
}

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2024-08-01 05:06:09

《从缺陷中学习C/C++》——6.4 临时对象的生存期的相关文章

《从缺陷中学习C/C++》——6.13 临时变量内存不能返回

6.13 临时变量内存不能返回 从缺陷中学习C/C++ 代码示例 char *initialize() { char str[300]; char* ptr = str; return ptr; } void useMyStr(char * str){ char tmp[300] = "123"; printf("%s\n", tmp); printf("%s\n", str); } int main() { char *myStr = init

《从缺陷中学习C/C++》——6.17 String对象何时需delete

6.17 String对象何时需delete 从缺陷中学习C/C++ 代码示例 int main() { string str1("stack-allocated str1"); string str2 = "stack-allocated str2"; string* str3 = new string("heap-allocated str3"); return 0; } 现象&后果 程序在运行时发生内存泄露. Bug分析 程序中使用

《从缺陷中学习C/C++》——6.16 结构体成员内存对齐问题

6.16 结构体成员内存对齐问题 从缺陷中学习C/C++ 代码示例 struct{ char flag; int i; } foo; int main() { foo.flag = 'T'; int pi = (int )(&foo.flag + 1); *pi = 0x01020304; printf("flag=%c, i=%x\n", foo.flag, foo.i); return 0; } 现象&后果 代码中定义了一个结构体,包括一个字符成员flag和整型成员

《从缺陷中学习C/C++》导读

前言 从缺陷中学习C/C++ 这是一本在研究大量C/C++程序Bug基础上集结而成的书! 这是一本汇集众多一线C/C++编程人员智慧的书! 这是一本让您学好C/C++,绕过编程陷阱和障碍的必备案头书! 为什么写这样一本书 在不同的项目或产品中,不同的开发人员重复着同样的Bug,甚至同一个人重复相同的Bug.如果将时间周期拉得更长一些看:一个程序员,从刚毕业参加工作到具备丰富编程经验,从一个新手到成为专家,在这个过程中,每个人都在重复着前人走过的弯路,重复着同样的编程错误.测试人员在日常工作中积累

《从缺陷中学习C/C++》——6.18 小结

6.18 小结 从缺陷中学习C/C++ C/C++内存使用是一个深入的话题.内存使用是对内存申请.读写.释放过程的安排与统筹,从而实现内存的正确.高效使用.本章主要从正确性上讲解了内存使用的全过程,包含了常见的错误案例.希望通过本章节的内容,使读者对C/C++内存使用有正确的了解和认识. 本文仅用于学习和交流目的,不代表异步社区观点.非商业转载请注明作译者.出处,并保留本文的原始链接.

《从缺陷中学习C/C++》——6.3 数组传参时的sizeof

6.3 数组传参时的sizeof 从缺陷中学习C/C++ 代码示例 void copy(int a[], int b[]) { memcpy(b, a, sizeof(a)); } 现象&结果 copy函数执行后,内存中的内容与设想不符,目标数组b中的内容不完整,没有把源数组a中的内容全部复制过来. Bug分析 memcpy函数的原型是void memcpy(void dest, const void *src, size_t n);,它的功能是从源src所指的内存地址的起始位置开始复制n个字节

《从缺陷中学习C/C++》——6.5 变量的作用域

6.5 变量的作用域 从缺陷中学习C/C++代码示例 char *str = NULL; if(!str) { char * str = (char*) malloc (100); if(!str) { return -1; } str[0] = 'a'; } printf("%c\n", str[0]); 现象&结果程序执行时出现coredump. Bug分析程序出现coredump的原因是代码printf("%cn",str[0])中使用的str是空指针

《从缺陷中学习C/C++》——6.8 指针释放后再次使用

6.8 指针释放后再次使用 从缺陷中学习C/C++代码示例 class MyClass{ private: int m_val; public: MyClass(int value){ m_val = value; printf("new class A\n"); } void getValue(){ printf("%d\n",m_val); } }; void function_a() { MyClass *A = new MyClass (1); functi

《从缺陷中学习C/C++》——6.14 正确使用引用参数和引用返回值

6.14 正确使用引用参数和引用返回值 从缺陷中学习C/C++代码示例 int &add(int n, int m) { n = n + m; return n; } int main() { int i = 10; int b = add(i, 1); cout << b << endl; return 0; } 现象&后果预期的输出结果是11,但实际输出的结果不确定. Bug分析add函数是一个函数引用,而add函数的返回值是形参n,形参是函数内的局部变量,函数