C++ Primer 第 5 版中发现的错误 shared_ptr<int>
Error spotted in C++ Primer 5th edition shared_ptr<int>
您好,我正在阅读 C++ 入门第 5 版,我想我在 shared_ptr 部分发现了一个错误。首先,我正在编写代码和他们给出的解释。然后我会写下我认为的错误和我认为实际发生的事情。代码如下:
shared_ptr<int> p(new int(42));// reference count is 1
int *q = p.get();// ok: but don't use q in any way that might delete its pointer
{//new block started
shared_ptr<int>(q);
}// block ends, q is destroyed, and the memory to which q points is freed
int foo = *p;// undefined; the memory to which p points was freed
他们给出的解释如下:
In this case, both p and q point to the same memory. Because they were created independently from each other, each has a reference count of 1. When the block in which q was defined ends, q is destroyed. Destroying q frees the memory to which q points. That makes p into a dangling pointer, meaning that what happens when we attempt to use p is undefined. Moreover, when p is destroyed, the pointer to that memory will be deleted a second time.
现在我认为错误是语句“当定义 q 的块结束时,q 是 destroyed.Destroying q 释放 q 指向的内存。 " 以及他们给出的为什么 p 是悬空指针的推理是错误的。以下是我为什么 p 是悬空指针以及为什么第一个引用的语句是错误的原因。
- 当定义 q 的块结束时,
q
被销毁。但是 q
指向的内存没有被释放,因为 q
是一个内置指针而不是 shared_ptr。并且除非我们明确地写 delete q
相应的内存将不会被释放。
- 现在,在新块中,我们使用 q 创建了一个临时 shared_ptr。但是这个临时独立于
p
。因此,当这个内部块结束时,临时文件被销毁,因此内存被释放。但请注意 p
仍然指向已释放的相同内存。所以 p
现在是一个悬挂指针,在语句 int foo=*p
中使用 p
是未定义的。
我认为这是对为什么 p 是悬挂指针的正确解释,也是应该存在的更正。有人可以确认这是正确的还是我做错了什么?
正如您正确指出的那样,文本描述和代码中的注释都不符合代码。他们更符合这样的代码:
shared_ptr<int> p(new int(42));// reference count is 1
{//new block started
shared_ptr<int> q(p.get());
}// block ends, q is destroyed, and the memory to which q points is freed
int foo = *p;// undefined; the memory to which p points was freed
如果我猜的话,我会说这就是示例最初的样子,然后有人决定引入原始指针,但没有意识到它也需要更改注释和文本。
第六次印刷,您所指的内容略有不同,如下:
shared_ptr<int> p(new int(42)); // reference count is 1
int *q = p.get(); // ok: but don't use q in any way that might delete its pointer
{ // new block
// undefined: two independent shared_ptrs point to the same memory
auto local = shared_ptr<int>(q);
} // block ends, local is destroyed, and the memory to which p and q points is freed
int foo = *p; // undefined; the memory to which p points was freed
Here, p
, q
, and local
all point to the same memory. Because p
and local
were created independently from one another, each has a reference count of 1. When the inner block ends, local
is destroyed. Because local
’s reference count is 1, the memory to which it points will be freed. That makes p
and q
into a dangling pointers; what happens when we attempt to use p
or q
is undefined. Moreover, when p
is destroyed, the pointer to that memory will be deleted a second time.
我认为 author's errata page 不再受管理。
C++ Primer 第 5 版以及您的解释在尝试解释该程序时犯了一个常见错误。注意语句:
shared_ptr<int>(q);
创建一个名为 q
的新临时文件,而不是使用 q
作为 shared_ptr
构造函数的参数创建新临时文件。下面的示例代码显示了这一点:
#include <iostream>
using namespace std;
struct NAME
{
int p = 0;
NAME()
{
std::cout<<"default constructor"<<std::endl;
}
NAME(int d): p(d)
{
std::cout<<"d: "<<d<<" p: "<<p<<std::endl;
}
NAME(const NAME& n)
{
std::cout<<"const copy constructor"<<std::endl;
}
NAME(NAME& n)
{
std::cout<<"non const copy constructor"<<std::endl;
}
~NAME(){
std::cout<<"destructor: "<<p<<std::endl;
}
};
int main()
{
cout << "Hello World" << endl;
NAME (4);//calls converting constructor
//after the completion of the above full statement the temporary is destroyed and hence you get a destructor call in the output
NAME k;//calls default constructor
std::cout<<"k.p: "<<k.p<<std::endl;
NAME(l);//this creates a temporary named l instead of creating a temporary using l as parameter to NAME's constructor ( in particular,default constructor)
NAME{l};//this creates a temporary using l as parameter to NAME's constructor with non-const copy constructor
return 0;
}
你解释的第二点是正确的只有当我们使用shared_ptr<int>{q};
而不是shared_ptr<int>(q);
。
这意味着:
由于作者使用了 shared_ptr<int>(q);
,因此创建了一个名为 q
的局部变量,它是一个智能指针,而不是来自外部作用域的内置指针。
这个局部变量 q
与外部范围的 p
或 q
无关 并且因此当这个本地 q
超出范围时 shared_ptr 的析构函数被调用。但请注意外部 p
或 q
指向的内存 未释放 .
所以之后我们写int foo = *p;
就没有未定义的行为了。
下面的 code 显示 shared_ptr<int>(q);
定义了一个名为 q
的局部变量,而不是使用 q
作为参数的临时变量。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
cout << "Hello World" << endl;
shared_ptr<int> p(new int(42)); // reference count is 1
int *q = p.get(); // ok: but don't use q in any way that might delete its pointer
std::cout<<"q's address "<<&q<<std::endl;
std::cout<<"p's address "<<&p<<std::endl;
{ // new block
shared_ptr<int>(q);
std::cout<<"new q's address "<<&q<<std::endl;
std::cout<<"new q's value "<<(*q)<<std::endl;//this produces segmentation fault
} // block ends, local is destroyed
int foo = *p; // this is ok
return 0;
}
在上面的代码中,如果我们尝试使用 *q
访问本地 q
的值,那么我们将得到 未定义的行为(这可能会使program/segmentation 错误),因为我们取消引用了一个空指针。如果我们删除这个 *q
那么程序就没有未定义的行为。
现在即使在本书的下一版(第 6 版)中,作者也使用了 auto local = shared_ptr<int>(q);
,而他本可以使用 shared_ptr<int>{q};
来表达他的观点。
您好,我正在阅读 C++ 入门第 5 版,我想我在 shared_ptr 部分发现了一个错误。首先,我正在编写代码和他们给出的解释。然后我会写下我认为的错误和我认为实际发生的事情。代码如下:
shared_ptr<int> p(new int(42));// reference count is 1
int *q = p.get();// ok: but don't use q in any way that might delete its pointer
{//new block started
shared_ptr<int>(q);
}// block ends, q is destroyed, and the memory to which q points is freed
int foo = *p;// undefined; the memory to which p points was freed
他们给出的解释如下:
In this case, both p and q point to the same memory. Because they were created independently from each other, each has a reference count of 1. When the block in which q was defined ends, q is destroyed. Destroying q frees the memory to which q points. That makes p into a dangling pointer, meaning that what happens when we attempt to use p is undefined. Moreover, when p is destroyed, the pointer to that memory will be deleted a second time.
现在我认为错误是语句“当定义 q 的块结束时,q 是 destroyed.Destroying q 释放 q 指向的内存。 " 以及他们给出的为什么 p 是悬空指针的推理是错误的。以下是我为什么 p 是悬空指针以及为什么第一个引用的语句是错误的原因。
- 当定义 q 的块结束时,
q
被销毁。但是q
指向的内存没有被释放,因为q
是一个内置指针而不是 shared_ptr。并且除非我们明确地写 deleteq
相应的内存将不会被释放。 - 现在,在新块中,我们使用 q 创建了一个临时 shared_ptr。但是这个临时独立于
p
。因此,当这个内部块结束时,临时文件被销毁,因此内存被释放。但请注意p
仍然指向已释放的相同内存。所以p
现在是一个悬挂指针,在语句int foo=*p
中使用p
是未定义的。
我认为这是对为什么 p 是悬挂指针的正确解释,也是应该存在的更正。有人可以确认这是正确的还是我做错了什么?
正如您正确指出的那样,文本描述和代码中的注释都不符合代码。他们更符合这样的代码:
shared_ptr<int> p(new int(42));// reference count is 1
{//new block started
shared_ptr<int> q(p.get());
}// block ends, q is destroyed, and the memory to which q points is freed
int foo = *p;// undefined; the memory to which p points was freed
如果我猜的话,我会说这就是示例最初的样子,然后有人决定引入原始指针,但没有意识到它也需要更改注释和文本。
第六次印刷,您所指的内容略有不同,如下:
shared_ptr<int> p(new int(42)); // reference count is 1
int *q = p.get(); // ok: but don't use q in any way that might delete its pointer
{ // new block
// undefined: two independent shared_ptrs point to the same memory
auto local = shared_ptr<int>(q);
} // block ends, local is destroyed, and the memory to which p and q points is freed
int foo = *p; // undefined; the memory to which p points was freed
Here,
p
,q
, andlocal
all point to the same memory. Becausep
andlocal
were created independently from one another, each has a reference count of 1. When the inner block ends,local
is destroyed. Becauselocal
’s reference count is 1, the memory to which it points will be freed. That makesp
andq
into a dangling pointers; what happens when we attempt to usep
orq
is undefined. Moreover, whenp
is destroyed, the pointer to that memory will be deleted a second time.
我认为 author's errata page 不再受管理。
C++ Primer 第 5 版以及您的解释在尝试解释该程序时犯了一个常见错误。注意语句:
shared_ptr<int>(q);
创建一个名为 q
的新临时文件,而不是使用 q
作为 shared_ptr
构造函数的参数创建新临时文件。下面的示例代码显示了这一点:
#include <iostream>
using namespace std;
struct NAME
{
int p = 0;
NAME()
{
std::cout<<"default constructor"<<std::endl;
}
NAME(int d): p(d)
{
std::cout<<"d: "<<d<<" p: "<<p<<std::endl;
}
NAME(const NAME& n)
{
std::cout<<"const copy constructor"<<std::endl;
}
NAME(NAME& n)
{
std::cout<<"non const copy constructor"<<std::endl;
}
~NAME(){
std::cout<<"destructor: "<<p<<std::endl;
}
};
int main()
{
cout << "Hello World" << endl;
NAME (4);//calls converting constructor
//after the completion of the above full statement the temporary is destroyed and hence you get a destructor call in the output
NAME k;//calls default constructor
std::cout<<"k.p: "<<k.p<<std::endl;
NAME(l);//this creates a temporary named l instead of creating a temporary using l as parameter to NAME's constructor ( in particular,default constructor)
NAME{l};//this creates a temporary using l as parameter to NAME's constructor with non-const copy constructor
return 0;
}
你解释的第二点是正确的只有当我们使用shared_ptr<int>{q};
而不是shared_ptr<int>(q);
。
这意味着:
由于作者使用了
shared_ptr<int>(q);
,因此创建了一个名为q
的局部变量,它是一个智能指针,而不是来自外部作用域的内置指针。这个局部变量
q
与外部范围的p
或q
无关 并且因此当这个本地q
超出范围时 shared_ptr 的析构函数被调用。但请注意外部p
或q
指向的内存 未释放 .所以之后我们写
int foo = *p;
就没有未定义的行为了。
下面的 code 显示 shared_ptr<int>(q);
定义了一个名为 q
的局部变量,而不是使用 q
作为参数的临时变量。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
cout << "Hello World" << endl;
shared_ptr<int> p(new int(42)); // reference count is 1
int *q = p.get(); // ok: but don't use q in any way that might delete its pointer
std::cout<<"q's address "<<&q<<std::endl;
std::cout<<"p's address "<<&p<<std::endl;
{ // new block
shared_ptr<int>(q);
std::cout<<"new q's address "<<&q<<std::endl;
std::cout<<"new q's value "<<(*q)<<std::endl;//this produces segmentation fault
} // block ends, local is destroyed
int foo = *p; // this is ok
return 0;
}
在上面的代码中,如果我们尝试使用 *q
访问本地 q
的值,那么我们将得到 未定义的行为(这可能会使program/segmentation 错误),因为我们取消引用了一个空指针。如果我们删除这个 *q
那么程序就没有未定义的行为。
现在即使在本书的下一版(第 6 版)中,作者也使用了 auto local = shared_ptr<int>(q);
,而他本可以使用 shared_ptr<int>{q};
来表达他的观点。