创建移动赋值函数,不断获取"pointer being freed was not allocated"
Creating a move assignment function, keep getting "pointer being freed was not allocated"
我正在尝试创建一个移动分配函数,但我不断得到 "pointer being freed was not allocated"
const MyString& MyString::operator=(MyString&& move){
cout<< "Move Assignment" << endl;
if(this != &move){
delete[] str;
len = move.len;
for(int i = 0; i<len;i++){
str[i] = move.str[i];
}
move.str=nullptr;
move.len = 0;
return *this;
}
return *this;
}
a.out(37068,0x1000b45c0) malloc:* 对象 0x1001025a0 错误:未分配正在释放的指针
a.out(37068,0x1000b45c0) malloc: * 在 malloc_error_break 中设置断点以调试
这个:
delete[] str;
删除 str
。但是然后:
str[i] = move.str[i];
str
被删除。所以这是未定义的行为。
反正这不是一招怎么办。移动的重点是避免复制字符串。假设 str
是 char*
,那么正确的实现如下(参数的通用名称是 rhs
,意思是 "right hand side"):
MyString& MyString::operator=(MyString&& rhs) noexcept
{
std::swap(len, rhs.len);
std::swap(str, rhs.str);
return *this;
}
再说一次:只有当 str
只是一个指针时,这才是正确的实现。请注意,该实现不会删除任何内容。删除将发生在 rhs
的析构函数中。 noexcept
说明符不是必需的,但由于此实现永远不会抛出异常,因此将其标记为 noexcept
允许编译器进行更多优化。
除了Nikos C.'s :
交换不是唯一的解决方案 – 但它是一种非常优雅的解决方案:您保留目标字符串的内存以在源字符串中重复使用。虽然到目前为止还不错,但您可能希望 re-start 在移动后使用空字符串。同样,您不应该删除内存,它非常适合 re-used。所以你只需将长度设置为 0.
但是,那么你需要单独记住,还有多少字符适合内存。但这无论如何都是有用的。想一想,每次追加单个字符时,您是否希望 re-allocate 字符串的内存?
很可能不会。所以你会添加一些额外的内存(例如,如果你 运行 内存不足,则将容量加倍)。全部加在一起:
class MyString
{
size_t length;
size_t capacity;
char* data;
public:
MyString& operator=(MyString&& other)
{
if(&other != this)
{
std::swap(data, other.data); // as in Nikos' answer
std::swap(capacity, other.capacity);
length = other.length;
other.length = 0; // restart with empty string
// still you have quite a bit of
// memory already reserved
}
return *this;
}
};
请注意,这是 可选的 ,但实际上,您可能会让人们为他们可能不需要的东西付费 – 如果他们不重复使用从中移出的对象。 ..
我正在尝试创建一个移动分配函数,但我不断得到 "pointer being freed was not allocated"
const MyString& MyString::operator=(MyString&& move){
cout<< "Move Assignment" << endl;
if(this != &move){
delete[] str;
len = move.len;
for(int i = 0; i<len;i++){
str[i] = move.str[i];
}
move.str=nullptr;
move.len = 0;
return *this;
}
return *this;
}
a.out(37068,0x1000b45c0) malloc:* 对象 0x1001025a0 错误:未分配正在释放的指针 a.out(37068,0x1000b45c0) malloc: * 在 malloc_error_break 中设置断点以调试
这个:
delete[] str;
删除 str
。但是然后:
str[i] = move.str[i];
str
被删除。所以这是未定义的行为。
反正这不是一招怎么办。移动的重点是避免复制字符串。假设 str
是 char*
,那么正确的实现如下(参数的通用名称是 rhs
,意思是 "right hand side"):
MyString& MyString::operator=(MyString&& rhs) noexcept
{
std::swap(len, rhs.len);
std::swap(str, rhs.str);
return *this;
}
再说一次:只有当 str
只是一个指针时,这才是正确的实现。请注意,该实现不会删除任何内容。删除将发生在 rhs
的析构函数中。 noexcept
说明符不是必需的,但由于此实现永远不会抛出异常,因此将其标记为 noexcept
允许编译器进行更多优化。
除了Nikos C.'s
交换不是唯一的解决方案 – 但它是一种非常优雅的解决方案:您保留目标字符串的内存以在源字符串中重复使用。虽然到目前为止还不错,但您可能希望 re-start 在移动后使用空字符串。同样,您不应该删除内存,它非常适合 re-used。所以你只需将长度设置为 0.
但是,那么你需要单独记住,还有多少字符适合内存。但这无论如何都是有用的。想一想,每次追加单个字符时,您是否希望 re-allocate 字符串的内存?
很可能不会。所以你会添加一些额外的内存(例如,如果你 运行 内存不足,则将容量加倍)。全部加在一起:
class MyString
{
size_t length;
size_t capacity;
char* data;
public:
MyString& operator=(MyString&& other)
{
if(&other != this)
{
std::swap(data, other.data); // as in Nikos' answer
std::swap(capacity, other.capacity);
length = other.length;
other.length = 0; // restart with empty string
// still you have quite a bit of
// memory already reserved
}
return *this;
}
};
请注意,这是 可选的 ,但实际上,您可能会让人们为他们可能不需要的东西付费 – 如果他们不重复使用从中移出的对象。 ..