再会。自 90 年代末以来我没有使用 C++ 知识后,我正在更新我的 C++ 知识,并且正在快速了解新事物。今天,我的问题是关于共享指针和结构。
这是我的代码:
#include <memory>
struct A {
int x;
};
int main() {
shared_ptr<struct A> y;
y->x =0;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译字符串:
g++ -Wall -Wpedantic --std=gnu++11 -g test.cpp -o test
Run Code Online (Sandbox Code Playgroud)
valgrind memcheck 指出第 11 行有一个“大小为 4 的无效写入”,即 y->x = 0
所以,我的问题是:为什么会有无效写入?我的理解——显然是错误的——是 shared_ptr 惯用语将处理它所指向的东西的内存分配和解除分配,而且据我所知,当我使用它指向原始类型和类时,确实会发生这种情况,但是这种将它与结构一起使用的情况让我感到困惑。
我试图弄清楚的真正用例是使用智能指针来存储结构 sockaddr_in,但我认为我应该(重新)学习爬行,然后再学习构建指向智能指针之前定义的对象的智能指针一个被广泛接受的东西。
谢谢。
下面是共享指针的示例代码。我在花括号范围内定义了一个共享指针。sp1 由新的 A(计数器 = 1)初始化,并将 sp1 分配给 sp2(复制和/或赋值将计数器加 1,因此计数器 = 2)。我一直认为当计数器变为 0 时会调用 A 的析构函数。但在我的情况下,智能指针即将超出范围(通过花括号)时,计数器为 2。
我的问题是:谁将计数器从 2 更改为 0?
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
~A(){
std::cout << "~A" << std::endl;
}
};
int main(){
{
shared_ptr<A> sp1 (new A);
shared_ptr<A> sp2 = sp1;
std::cout << "sp1 count = " << sp1.use_count() << std::endl;
std::cout << "sp2 count = " << sp2.use_count() << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑: 链接到智能指针上的论文
输出:
sp1 计数 …
如果我在具有自动存储持续时间(即存储在堆栈上)的对象上应用智能指针(scoped_ptr,unique_ptr或shared_ptr),是否会出现问题?我不认为在这两种情况下(有和没有智能指针),如果没有更多的指针指向它们,它们将被删除。指针本身总是具有自动存储期限,即如果超出范围,它们将被删除。
我们可以将 [] 运算符或 ++ 与唯一指针或 shared_pointer 一起使用吗?当我们将它用于原始指针时
int * a = new int[10];
a[0] = 2; // We can use [] operator;
Run Code Online (Sandbox Code Playgroud)
智能指针有类似的方法吗?
如果有,我应该什么时候使用它?
我有以下代码:
unsigned char* frame_buffer_data{ new unsigned char[data_size] };
glReadPixels(origin_x, origin_y, width, height, GL_BGR, GL_UNSIGNED_BYTE, frame_buffer_data);
Run Code Online (Sandbox Code Playgroud)
我想摆脱原始指针 ( frame_buffer_data) 并使用唯一指针。
试试这个:
std::unique_ptr<unsigned char> framebuffer_data(new unsigned char[data_size] );
Run Code Online (Sandbox Code Playgroud)
不起作用。
如何将唯一指针(或其他智能指针)传递给此函数?
调用后,glReadPixels我需要能够reinterpret cast确定数据类型并将数据写入文件,如下所示:
screenshot.write(reinterpret_cast<char*>(frame_buffer_data), data_size);
Run Code Online (Sandbox Code Playgroud) 虽然 C++11 中的共享指针和唯一指针都允许用户定义删除器,但它们有显着的语法差异,如下面的小示例所示:
#include "pch.h"
#include <memory>
class factory
{
public:
static factory * create() {
return new factory();
}
static void destroy(factory* fp) noexcept{
delete fp;
}
factory(const factory &) = delete;
factory& operator= (const factory &) = delete;
private:
char * p_;
factory() {
p_ = new char[100];
}
~factory() {
delete[] p_;
}
};
int main()
{
typedef void(*fp)(factory*);
auto del = [](factory * p) noexcept {
factory::destroy(p);
};
std::shared_ptr<factory> fsptr1(factory::create(), del);
std::shared_ptr<factory> fsptr2(factory::create(), del);
//notice the …Run Code Online (Sandbox Code Playgroud) 这个问题来自我试图了解智能指针的动机,在该指针周围创建一个包装类,以便您可以添加自定义析构函数。指针(和整数、布尔值、双精度数等)没有析构函数吗?
我目前正在做一个项目,更准确地说是一个七巧板游戏。我有段错误问题,我不明白为什么。
鉴于我有一个完整的项目,我将尝试简化问题:我有一个 GameManager 类,其中特别包含一个 Menu 对象(和其他东西,但我认为这并不重要。gameManager 用于初始化这个对象并管理它。菜单包含一个按钮向量(每个按钮都有一个 lambda 来在用户单击它时执行操作)。
std::vector<std::unique_ptr<Button>> buttons;
Run Code Online (Sandbox Code Playgroud)
为了说明它是如何工作的,我将举一个例子:如果用户点击“加载”按钮,游戏管理器将删除菜单中包含的当前按钮并在该菜单中添加新按钮。
void GameManager::initMainMenuButtons() {
...
menu -> addButton(std::unique_ptr<Button>(new Button(x1, y1, x2, y2, "Create",
[this]{
std::cout << "Create level" << std::endl;
menu->clear()
initCreateLevelButtons();
actionManager->setMenu(menu);
}
)));
...
}
Run Code Online (Sandbox Code Playgroud)
在该代码示例中,我有一个方法 initMainMenuButtons 可以在菜单中添加几个按钮,例如“加载”或“退出”。当用户单击“创建”时,我想更改界面(添加和删除按钮)。所以,要删除按钮,我调用方法 clear()
void Menu::clear() {
buttons.clear();
decorationPieces.clear(); // not interesting
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 unique_ptr,因此,我不必手动删除按钮。到目前为止,没问题:按钮的向量似乎是空的(大小为 0)。接下来,调用方法 initCreateLevelButtons()。此方法与 initMainMenu 非常相似:它在菜单中添加按钮,仅此而已。在此调用期间,按钮似乎正确添加到矢量中,我在最后打印了矢量的内容,矢量包含正确的按钮。
在那里,问题出现了:在调用 initCreateLevelButtons() 之后,当我想使用菜单时会出现段错误,因此actionManager->setMenu(menu);不起作用。我尝试打印 menu std::cout << menu << std::endl,并测试此指针是否为 nullptr,但它也不起作用。我不明白为什么菜单在 initCreateLevelButtons() 的最后一行似乎是正确的,然后就无效了。如果我不清除按钮的矢量(菜单->清除指令),程序可以工作,但是,最后一个按钮仍然在这里)。
我尝试使用原始指针,我注意到只要按钮没有被删除,程序就能够清除向量(如果我添加一个循环来删除按钮,就会出现问题),所以,我得出的结论是问题是按钮删除。我不明白为什么,我被卡住了。我不知道我解释得好不好,因为,正如我已经说过的,代码是整个项目的一部分,很难在不引入其他东西的情况下引入类。如果您需要详细信息或方法的完整代码,我可以提供。
可以使用函数的指针返回,这在很多方面都很有用,但是否建议从该返回值中获取引用?
#include <iostream>
#include <memory>
using namespace std;
unique_ptr<int> give_a_number(){
return std::make_unique<int>(6);
}
int main(){
int& ret = *give_a_number();
return ret;
}
Run Code Online (Sandbox Code Playgroud)
根据消毒剂,没有发生泄漏:
user@comp: Scrapbook$ g++ main.cpp -fsanitize=address -g
user@comp: Scrapbook$
Run Code Online (Sandbox Code Playgroud)
所以参考以某种方式被清理,但我不明白为什么。清理是如何发生的,甚至 unque_ptr 如何能够跟踪数据。这应该被视为安全行为吗?这是社区中公认的用法吗?
这是重现的最小示例:
源代码:
#include <memory>
#include <iostream>
class A : public std::enable_shared_from_this<A>
{
public:
A(std::weak_ptr<A> up) : up_(up)
{
std::cout << "A" << " has up_? " <<
((up_.lock()) ? "yes" : "no")
<< std::endl;
}
void grow()
{
if (dp_)
dp_->grow();
else
dp_ = std::make_shared<A>(weak_from_this());
}
private:
std::weak_ptr<A> up_;
std::shared_ptr<A> dp_;
};
int main()
{
auto wp = std::weak_ptr<A>();
A a(wp);
for (int i = 0; i < 3; ++i)
{
a.grow();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
原始日志:
clang++ minimal.cpp && …Run Code Online (Sandbox Code Playgroud) c++ ×10
smart-pointers ×10
pointers ×4
shared-ptr ×2
arrays ×1
destructor ×1
raw-pointer ×1
reference ×1
struct ×1
unique-ptr ×1
vector ×1
weak-ptr ×1