问题描述
我正在学习 C++,在我所有的“实验”中,我都试图了解临时对象(右值)的生命周期。
我的问题是:
有一个包含 const char* 指针的对象,当我想使用一个以“const char*”作为参数的构造函数时会发生什么?通常临时对象会自动销毁,但是以这种方式创建的指针会发生什么?
我现在不使用 std::string 或其他 c++11 类,因为我只是专注于理解右值。
以下示例:
class MyAwesomeClass {
private:
const char* data;
public:
MyAwesomeClass(const char* ptr) {
this->data = ptr;
}
MyAwesomeClass(MyAwesomeClass&& myAwesomeClassRVALUE) {
this->data = myAwesomeClassRVALUE.data;
myAwesomeClassRVALUE.data = nullptr;
}
~MyAwesomeClass() {
delete data;
}
};
int main() {
MyAwesomeClass s = "My Awesome Class' string data.";
return 0;
}
解决方法
通常临时对象会自动销毁,但是以这种方式创建的指针会发生什么?
指针本身就是对象。临时指针对象的情况与所有其他临时对象的情况相同。
您的示例删除了指向字符串文字的指针,因此程序的行为未定义。即使通过将指针传递给用 new[]
分配的数组来正确使用该类,它也会有一个损坏的赋值运算符。
至于右值,我能找到的示例中唯一的右值表达式是 nullptr
。
注意此答案基于之前对该问题的编辑,其中 MyAwesomeClass
是 String
类。
您的 String
类并不是真正的字符串类,因为它不拥有底层字符串数据。它更类似于std::string_view
。
我认为你有两条途径可以追求:
-
您的班级拥有基础数据。在这种情况下,该类是
std::string
的包装器,并且 std::stringdata member. Look up composition. No need to worry about lifetime as
std::string` 表现良好。 你的类就像一个指向另一个字符串的“指针/引用/视图”。在这种情况下,您有一个
const char*
和可能std::size_t
大小的数据成员。您基本上拥有std::string_view
(设计std::string_view
的智慧、专业知识和经验除外)。由于您不拥有底层数据,因此您无法对底层数据的生命周期做任何事情。类的用户必须确保它不会以指向过期对象的“YourStringView”结尾,就像他/她需要确保它不会以指向过期对象的引用/指针结尾一样。>
这两种场景的语义完全不同(作为对象和指向对象的指针之间的区别)。
无论如何,除了可能出于学习原因之外,我不建议您执行任何此类操作。 std::string_view
已经存在,所以只需使用它。如果您想要打印功能,请使用 fmt library 或 C++ 格式库(基于提到的 fmt 库)。
即使您出于学习目的决定这样做,我也强烈建议您研究这些替代方案并从它们的工作方式中学习。
MyAwesomeClass(const char* ptr)
{
this->data = ptr;
}
~MyAwesomeClass()
{
delete data;
}
哦,不,不,不!不!!
请查看 RAII 和 0/3/5 的规则。您的班级要么拥有指向的对象,要么不拥有。如果它拥有它,则它负责创建和删除它。如果没有,那么它也做不到。你不能有“一半的责任”,你负责删除它而不负责创建它。
在用户代码中,您应该永远需要手动管理内存。使用0的规则。
,快速回答是您的类不拥有数据,而只是原始指针。在某些情况下,您会发现删除运算符有问题。原始指针不是确保正确对象所有权的好工具。