c++菜鸡求助

2015-11-03 21:42:40 +08:00
 superhxnju

代码

#include <iostream>

using namespace std;

struct A{
  int a;
};

A & clone(A & a) {
  A * p;
  *p = a;
  cout << "p addr" << p << endl;
  return *p;
}

int main() {
  A a = A{3};
  A & r = a;
  cout << "r addr" << &r << endl;
  A & v = clone(r);
  cout << "v addr" << &v << endl;
  cout << a.a << " " << v.a << endl;
  v.a = 2;
  cout << a.a << " " << v.a << endl;
  delete &v;
  return 0;
}

输出

r addr0x7fff5514c938
p addr0x7fff78e62300
v addr0x7fff78e62300
3 3
3 2
a.out(22733,0x7fff77e0a000) malloc: *** error for object 0x7fff78e62300: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

参考书目: C++ Primer Plus 6th > 8 Adventure in Functions > Reference Variables(page 400 , pdf 中的 415 页)

A call to clone() conceals the call to new, making it simpler to forget to use delete later.

疑问:
- 函数 clone 中是否在堆中新分配了内存给*p?(个人认为不是,根据地址来看,地址属于栈)
- 为什么书中写到是隐式调用了 new ,但是当 delete 的时候出现pointer being freed was not allocated的错误?


环境
- mac
- g++
- c++11

1464 次点击
所在节点    C
10 条回复
colatin
2015-11-03 21:53:46 +08:00
建议把 c 的指针学好先。
A *p; *p = a;
这里的 p 就是个野指针。*p=a 相当于在一个不知道什么地方的地方写了一个值。
superhxnju
2015-11-03 21:59:46 +08:00
@colatin 大概知道是个野指针,但就是书看到这里的时候很困惑。书里面的这段是我理解有误。。。还是就是有问题?
Ethaniz
2015-11-03 22:00:41 +08:00
没听说过 clone 会隐式调用 new 呢,你这里的情况是:在 clone 中声明了一个栈变量,类型是个指针,指向地址随机,然后把这个指针指向的地址赋上了 a 的值,然后又返回了这个指针指向的值的引用。函数调用结束,该指针消失。自始至终没有向堆申请任何空间,所以导致 delete 失败。
theoractice
2015-11-03 22:20:03 +08:00
http://book.douban.com/review/5472087/
这书是瞎写的吧。

Accelerated C++
Effective C++
More Effective C++
www.cplusplus.com/reference/
看这些足够了。
superhxnju
2015-11-03 22:22:23 +08:00
@theoractice 看的是 c++ primer plus ,重拾一下 c++
superhxnju
2015-11-03 22:24:36 +08:00
@theoractice 看看基础就行
znoodl
2015-11-03 22:43:09 +08:00
经典的不是 c++ primer 吗? 不带 plus ,不是一个作者,书里有 delete 的例子吗
superhxnju
2015-11-03 22:54:33 +08:00
@znoodl 被名字给欺骗了
SYP
2015-11-03 23:25:48 +08:00
这样的代码这本书还说的一本正经,还是放弃掉吧。
yangyanggnu
2015-11-04 09:38:38 +08:00
基本上,这,是作者的疏忽,但不能因此完全否定它的价值。





==============================================
***《 C++ Primer Plus (第 6 版)中文版》 勘误表***
联系: yangyangwithgnu@yeah.net
时间: 2013-9-24
==============================================

P268
错误: free_throws * pt;
修正: free_throws * pt = new free_throws;

P291
错误:在这两个模板函数中, recycle<blot *>(blot *) 被认为是更具体的
修正:在这两个模板函数中, recycle<blot>(blot *) 被认为是更具体的

P337
错误: static const LIMIT = 25;
修正: static const unsigned LIMIT = 25;

P386
错误: t4 = t1 + t2 + t3 先转换为 t4 = t1.operator+(t2 + t3) 再转换为 t4 = t1.operator+(t2.operator+(t3))
修正: t4 = t1 + t2 + t3 先转换为 t4 = t1.operator+(t2) + t3 再转换为 t4 = t1.operator+(t2).operator+(t3)

P387
错误:.*:成员指针运算符
修正:->:成员指针运算符

P428
错误: String boston("Boston");
修正: StringBad boston("Boston");

P431
错误:然后程序使用重载运算符>>列出了这些对象
修正:然后程序使用重载运算符<<列出了这些对象

P439
错误:最简单的办法是使用标准的 trcmp()函数
修正:最简单的办法是使用标准的 strcmp()函数

P440
错误: means.operator[][0] = 'r';
修正: means.operator[](0) = 'r';

P439
错误:因为内置的>运算符返回的是一个布尔值
修正:因为内置的<运算符返回的是一个布尔值

P478
错误: Cow(const Cow c& );
修正: Cow(const Cow & c);

P478
错误:提供一个 Stringlow()成员函数
修正:提供一个 stringlow()成员函数

P478
错误:提供 String()成员函数
修正:提供 stringup()成员函数

P505
错误: 这意味着,即使基类不需要显式析构函数提供服务,也不应该依赖于默认构造函数
修正: 这意味着,即使基类不需要显式析构函数提供服务,也不应该依赖于默认构造析构

P508
错误:半长轴
修正:长半轴

P510
错误: void Move(int nx, ny) = 0
修正: virtual void Move(int nx, ny) = 0

P525
错误:
Star::Star double() {...}
Star::Star const char * () {...}
修正:
Star::operator double() {...}
Star::operator const char * () {...}

P529
错误:派生类的有元函数
修正:派生类的友元函数

P532
错误: Cd(char * s1, char * s2, int n, double x);
修正: Cd(const char * s1, const char * s2, int n, double x);

P532
错误:派生出一个 Classic 类,并添加一组 char 成员
修正:派生出一个 Classic 类,并添加一个 char 数组成员

P532
错误: copy.Report()
修正: copy.Report();

P535
错误:所有元素度被初始化为指定值的数组
修正:所有元素都被初始化为指定值的数组

P544
错误:例如,在类声明中提出可以使用 average()函数。和包含一样,要实现这样的目的,可以在公有 Student::average()函数中使用私有 Student::Average()函数。
修正:例如,对于类 Student 需要提供的 Average()函数,与包含版本一样,私有继承版本同样可以借用 valarray 的 size()和 sum()方法来实现。

P549
错误:和私有私有继承一样
修正:和私有继承一样

P551
错误:这里使用两个独立的派生使基类( Worker )被继承
修正:从基类( Worker )继承出两个独立的派生类

P555
错误:
Enter waiter's name: Waldo Dropmaster
...
Enter singer's name: Sylvie Sirenne
修正:
Enter worker's name: Waldo Dropmaster
...
Enter worker's name: Sylvie Sirenne

P573
错误:只有一个 pop 变量
修正:只有一个 po 变量

P583
错误: template <> class SortedArray<const char char*>
修正: template <> class SortedArray<const char*>

P656
错误: string(const string & str, string size_type pos, size_type n = npos)
修正: string(const string & str, size_type pos, size_type n = npos)

P729
错误:将 li 重置为排序的 vi0 的内容
袖子:将 li 重置为未排序的 vi0 的内容

P773
错误: ofstream fout();
修正: ofstream fout;

P794
错误: Store 的构造函数应接受一个指定 ifstream 对象的参数
修正: Store 的构造函数应接受一个指定 ofstream 对象的参数

P835
错误:*pt = ai[i];
修正:*pt = ar[i];

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/233379

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX