访问另一个 class 中指向 class 的智能指针的属性时出现分段错误
segmentation fault when acessing attribute of an smart pointer to class, inside another class
我试着做这个:
#include <iostream>
#include <memory>
class B
{
public:
std::string var;
B()
{
var = "original";
}
void print()
{
std::cout << "composition " << std::endl;
}
};
class A
{
public:
int a_attribute = 10;
std::unique_ptr<B> b;
};
int main()
{
A a;
a.b->print();
}
这似乎工作正常,除非我尝试访问 B 的属性,例如:
std::string test = a.b->var;
这会导致 segmentation fault
错误
为什么我没有收到 a.b->print();
的错误,但收到 a.b->var;
的段错误?
你的问题在这里,在A你有
std::unique_ptr<B> b;
这将创建一个指向 B 对象的智能指针。 但是它没有指向B对象。在使用它之前,您必须创建一个 B 对象并设置 'b' 指向它。
我不确切知道您想如何以及何时创建 B,但您可以这样做
A a;
a.b = std::make_unique<B>();
a.b->print();
这将使用默认构造函数创建一个新的 B 并使 'a.b' 指向它。这是
更有效的简写
A a;
B *b1 = new B;
a.b.reset(b1);
a.b->print();
它明确地创建了一个 B 然后设置 a.b 指向它。
请注意,您不必释放 B 对象。这就是智能指针的意义所在,他们会为您完成。
您问过为什么有些组合有效而有些无效。
您有未定义的行为。这可以做任何事情,包括最糟糕的,看起来有效。然后在圣诞节前夜的午夜,你最大的客户向你的系统提交了一个巨大的订单,然后它崩溃了。每个专业开发人员都遇到过这种情况。避免方法:提高编译器警告级别,永远不要忽略警告。使用类似 valgrind 或其他商业检查工具的工具。
对我来说,您发布的原始代码有效。为什么,因为调用的方法实际上不需要 B 对象中的任何数据。但是如果我改成这个
void print()
{
std::cout << "composition " << std::endl;
std::cout << var << std::endl;
}
它失败了,因为现在我们正在引用 B 对象中的数据,但是没有。
请注意,在不同的编译器上,您的原始代码将无法运行
我试着做这个:
#include <iostream>
#include <memory>
class B
{
public:
std::string var;
B()
{
var = "original";
}
void print()
{
std::cout << "composition " << std::endl;
}
};
class A
{
public:
int a_attribute = 10;
std::unique_ptr<B> b;
};
int main()
{
A a;
a.b->print();
}
这似乎工作正常,除非我尝试访问 B 的属性,例如:
std::string test = a.b->var;
这会导致 segmentation fault
错误
为什么我没有收到 a.b->print();
的错误,但收到 a.b->var;
的段错误?
你的问题在这里,在A你有
std::unique_ptr<B> b;
这将创建一个指向 B 对象的智能指针。 但是它没有指向B对象。在使用它之前,您必须创建一个 B 对象并设置 'b' 指向它。
我不确切知道您想如何以及何时创建 B,但您可以这样做
A a;
a.b = std::make_unique<B>();
a.b->print();
这将使用默认构造函数创建一个新的 B 并使 'a.b' 指向它。这是
更有效的简写A a;
B *b1 = new B;
a.b.reset(b1);
a.b->print();
它明确地创建了一个 B 然后设置 a.b 指向它。
请注意,您不必释放 B 对象。这就是智能指针的意义所在,他们会为您完成。
您问过为什么有些组合有效而有些无效。
您有未定义的行为。这可以做任何事情,包括最糟糕的,看起来有效。然后在圣诞节前夜的午夜,你最大的客户向你的系统提交了一个巨大的订单,然后它崩溃了。每个专业开发人员都遇到过这种情况。避免方法:提高编译器警告级别,永远不要忽略警告。使用类似 valgrind 或其他商业检查工具的工具。
对我来说,您发布的原始代码有效。为什么,因为调用的方法实际上不需要 B 对象中的任何数据。但是如果我改成这个
void print()
{
std::cout << "composition " << std::endl;
std::cout << var << std::endl;
}
它失败了,因为现在我们正在引用 B 对象中的数据,但是没有。
请注意,在不同的编译器上,您的原始代码将无法运行