我正在用SSO创建一个字符串,并且当字符串超过23个字符时,我想将指向堆内存的指针存储在堆栈数组中。我遇到的问题是,当我尝试删除分配在堆上的内存时出现错误。我知道我在正确的地址上调用delete,但是失败。谁知道为什么?代码如下:
->clear()
解决方案:在构造函数中,我分配了class kstring
{
public:
kstring()
{
}
kstring(const char* str)
{
size_ = std::strlen(str);
if (size_ + 1 > capacity_)
reserve(capacity_ + 1);
std::strcpy(data(), str);
}
void reserve(size_t capacity)
{
if (capacity <= capacity_ || capacity <= 24)
return;
char* alloc = new char[capacity];
std::cout << "Alloc: " << static_cast<void*>(alloc) << std::endl;
std::copy(data(), data() + size_, alloc);
if (on_heap())
delete[] data();
std::memcpy(data_, &alloc, sizeof(char*));
capacity_ = capacity;
}
char* data()
{
return capacity_ > 24 ? heap_ptr() : data_;
}
size_t size() const noexcept
{
return size_;
}
size_t capacity() const noexcept
{
return capacity_;
}
char& operator[](size_t n)
{
return data()[n];
}
~kstring()
{
if (on_heap())
{
std::cout << "Deleting: " << static_cast<void*>(data()) << std::endl;
delete[] data();
}
}
bool on_heap()
{
return capacity_ > 24;
}
char* heap_ptr()
{
char* ptr = nullptr;
std::memcpy(&ptr, data_, sizeof(char*));
return ptr;
}
char data_[24] = {0};
private:
size_t size_ = 0;
size_t capacity_ = 24;
};
int main()
{
{
kstring str("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
}
return 0;
}
个字节而不是capacity_ + 1
个字节,导致堆损坏。
答案 0 :(得分:1)
kstring(const char* str)
{
size_ = std::strlen(str);
if (size_ + 1 > capacity_)
reserve(capacity_ + 1);
std::strcpy(data(), str);
}
这有很多问题。
首先,将size_
设置为立即可用的大小。但是,如果您查看reserve
,它将尝试复制字符串中已有的size_
个字节。
第二,您尝试保留的金额为capacity_ + 1
。但是没有理由认为这足以容纳您要复制的字符串。
这可能更接近您想要的:
kstring(const char* str)
{
size_t new_size = std::strlen(str) + 1;
if (new_size > capacity_)
reserve(new_size + 1);
std::strcpy(data(), str);
size_ = new_size - 1;
}
请注意,在调用size_
之前我们不会更改reserve
,因此不会超出范围。还要注意,我们告诉reserve
我们需要保留的正确字节数。