为什么我的r值在成功分配给对象后被删除?
究竟何时调用析构函数?最初,我认为应该在我们使用时调用析构函数:
delete [] str;
delete [] str;
然后,当我遇到“移动分配”主题时,我注意到rhs.str在我的move assignment方法中将 my设为 NULL 之后直接调用了析构函数。
主程序
int main() {
Mystring a{"Hello"}; // Overloaded constructor
a = Mystring{"Hola"}; // Overloaded constructor then move assignment
// cout << a.get_str() << endl;
a = "Bonjour"; // Overloaded constructor then move assignment
return 0;
}
我的字符串.h
#ifndef _MYSTRING_H_
#define _MYSTRING_H_
class Mystring
{
private:
char *str; // pointer to a char[] that holds a C-style string
public:
Mystring(); // No-args constructor
Mystring(const char *s); // Overloaded constructor
Mystring(const Mystring &source); // Copy constructor
Mystring(Mystring &&source); // Move constructor
~Mystring(); // Destructor
Mystring &operator=(const Mystring &rhs); // Copy assignment
Mystring &operator=(Mystring &&rhs); // Move assignment
void display() const;
int get_length() const; // getters
const char *get_str() const;
};
#endif // _MYSTRING_H_
我的字符串.cpp
// No-args constructor
Mystring::Mystring()
: str{nullptr} {
str = new char[1];
*str = ' ';
}
// Overloaded constructor
Mystring::Mystring(const char *s)
: str {nullptr} {
if (s==nullptr) {
str = new char[1];
*str = ' ';
} else {
str = new char[strlen(s)+1];
strcpy(str, s);
}
}
// Copy constructor
Mystring::Mystring(const Mystring &source)
: str{nullptr} {
str = new char[strlen(source.str)+ 1];
strcpy(str, source.str);
std::cout << "Copy constructor used" << std::endl;
}
// Move constructor
Mystring::Mystring(Mystring &&source)
: str(source.str)
{
source.str = nullptr;
std::cout << "Move constructor used" << std::endl;
}
// Destructor
Mystring::~Mystring()
{
if (str == nullptr) {
std::cout << "Calling destructor for Mystring : nullptr" << std::endl;
} else {
std::cout << "Calling destructor for Mystring : " << str << std::endl;
}
delete [] str;
}
// Copy assignment
Mystring &Mystring::operator=(const Mystring &rhs) {
std::cout << "Using copy assignment" << std::endl;
if (this == &rhs)
return *this;
delete [] str;
str = new char[strlen(rhs.str) + 1];
strcpy(str, rhs.str);
return *this;
}
//Move assignment
Mystring &Mystring::operator=(Mystring &&rhs) {
std::cout << "Using move assignment" << std::endl;
if (this == &rhs)
return *this;
delete [] this->str;
this->str = rhs.str;
rhs.str = nullptr;
return *this;
}
输出如下:
Using move assignment
Calling destructor for Mystring : nullptr
Using move assignment
Calling destructor for Mystring : nullptr
Calling destructor for Mystring : Bonjour
我试过调试,但我不知道为什么当我没有显式调用时它会进入 Destructor 方法
delete [] str // or maybe
delete [] rhs.str
正如您在输出中看到的,每次移动分配后都会删除我的 r 值。我认为每个对象至少应该在删除之前被删除return 0;
回答
究竟何时调用析构函数?
当然,当对象被销毁时会调用析构函数。何时发生取决于对象的存储持续时间。
我认为应该在我们使用时调用析构函数:
这是具有动态存储持续时间的对象数组被销毁的一种情况。也就是说,在str这些对象的类型中char,具有简单的析构函数,因此在实践中没有什么可以“调用”的。
int main() { Mystring a{"Hello"};
该变量a具有自动存储持续时间。该对象在声明它的范围的末尾(在函数的末尾main)被销毁。这是您在输出中最后看到的析构函数。
a = Mystring{"Hola"};
这里创建了一个临时对象,用作赋值运算符的右手操作数。临时对象在完整表达式的末尾即在赋值之后被销毁。这是您在输出中首先看到的析构函数。
a = "Bonjour";
这与之前检查的代码段相同,只是临时对象不太明显,因为您使用的是类的隐式转换构造函数。此对象的析构函数是您在输出中的第一个和最后一个之间看到的析构函数。
聚苯乙烯
#define _MYSTRING_H_
该名称保留给语言实现。通过定义它,您的程序将具有未定义的行为。您应该使用另一个未保留的标题保护。