【发布时间】:2017-07-06 03:52:40
【问题描述】:
我很好奇 delete 操作符在基指针上调用 delete 时如何知道派生类的大小,这是一个最小的例子:
class IVariant
{
public:
virtual ~IVariant() = default;
virtual void print_value() = 0;
};
template<typename T>
class Variant: public IVariant {};
template<>
class Variant<int>: public IVariant
{
private:
int m_integer;
public:
Variant(int integer): m_integer(integer) {}
void print_value() override
{
printf("integer: %i\n", m_integer);
}
};
template<>
class Variant<double>: public IVariant
{
private:
double m_dbl;
public:
Variant(double val): m_dbl(val) {}
void print_value() override
{
printf("double: %g\n", m_dbl);
}
};
template<>
class Variant<std::string>: public IVariant
{
private:
std::string m_string;
public:
Variant(const std::string& string): m_string(string) {}
void print_value() override
{
printf("string: %s\n", m_string.c_str());
}
};
测试:
int main()
{
IVariant* int_var = new Variant<int>(100);
IVariant* dbl_var = new Variant<double>(100.0f);
IVariant* str_var = new Variant<std::string>("the value is 100\n");
int_var->print_value();
dbl_var->print_value();
str_var->print_value();
delete int_var;
delete dbl_var;
delete str_var;
}
delete 运算符仅从基指针就正确地知道 int_var = variant<int> 所以释放了 4 个字节,dbl_var = variant<double> 所以释放了 8 个字节,str_var = variant<std::string> 所以它释放了 28 个字节。
但它怎么知道呢? new 运算符是否存储大小和指针,然后删除运算符可以使用它来释放正确的字节数?我知道这就是 delete[] 对数组起作用的方式,但是在派生类方面我找不到任何信息
【问题讨论】:
-
这是实现定义的。您需要指定您想了解的实现以获得有意义的答案。
-
简而言之,是的。堆分配具有已创建的每个对象的大小和类型信息。调用 delete 将转到查找表并释放给定对象的相应字节数。
-
标准库
operator new的默认堆内存分配器“知道”它分配给您的每个指针拥有多少内存。它负责清理,原因是运行时正确调用了适当的析构函数。 -
@callyalater "大小和类型信息" - 堆分配器有哪些类型信息?
-
@NirFriedman 在 typedef、using 或成员变量上下文中使用时,某些实现将存储模板类型大小(我的意思是类型信息)以确定要使用的偏移量并提供类型检查在运行时。但是,类型信息(如果有)是实现定义的。
标签: c++