初学者和CPP课程
beginner and cpp class
我在这里使用"构造函数和析构函数"下的代码
基本上,我想将其与下面的指针结构相结合"指向类的指针"(下面一点),我觉得真的很整洁。
现在这有效:
int main () {
CRectangle * prect; //l2
CRectangle rect (3,4); //l3
prect = ▭ //l4
cout << "rect area: " << (*prect).area() << endl;
return 0;
}
我的问题是,我们能用更优雅的方法代替l2-l4吗?不需要在第 3 行创建矩形?
要在不需要任何自动变量(例如上面的代码中的rect
)的情况下创建对象,必须使用 new
运算符。使用 new
运算符创建的对象存储在自由存储区中,new
表达式的计算结果为指向新创建对象的指针。
现在,人们可以继续说,new
运算符是答案,仅此而已,但实际上并非如此:它没有回答用更优雅的解决方案替换这几行的问题,因为它不会是一个。
这个答案的其余部分是关于如何使用new
的切线。
不同,存储在免费存储中的对象不会自动销毁,而是它们的生命周期和销毁由delete
操作员控制(您应该删除不再需要释放资源的对象)。为了确保销毁,应始终将指针从new
表达式存储到所谓的智能指针中。一个好的、简单的规则:仅在智能指针构造函数中使用 new
运算符(除非您知道自己在做什么)。
C++11 中有几个智能指针,而该标准的早期版本只定义了一个,即auto_ptr
。也许是由于它的怪癖,或者仅仅是因为它得到了替代品,它实际上在 C++11 中被弃用了,并且不应该在新代码中使用,至少不应该在 C++11 中使用(现在,这是一种意见)。
智能指针使用示例:
boost::shared_ptr<CRectangle> shared_rect(new CRectange(3, 4));
std::unique_ptr<CRectangle> rect(new CRectangle(3, 4)); // C++11 only
// use smart pointers like like regular pointers; indirection through * or ->
// i.e. (*rect).area() or rect->area()
我也喜欢@eq-的答案,但除了动态内存分配之外,您还可以尝试放置新。(当我说"尝试"时,我并不是说这是做事的方式,但更像这样更值得深思。我不是想把你带到一个迷宫般的曲折的小段落,都一样。
char mem[sizeof(CRectangle)] alignas(CRectangle);
CRectangle *prect = new (mem) CRectangle(3, 4); // construct
std::cout
<< "rect area: " << prect->area()
<< std::endl;
prect->~CRectangle(); // destruct
在使用自定义分配器时,通常会使用放置 new。自定义分配器可以出于各种原因使用,但在我的工作中,它通常用于预分配策略(如池分配器或具有严格内存配置的嵌入式系统)。在这种情况下,放置 new 用于初始化具有自动存储类的内存。与原始 rect
对象一样,当代码超出范围时,对象的内存将变为无效。但是,CRectangle
构造函数可能会执行需要清理的初始化,因此在内存超出范围之前,会显式调用析构函数。
注意,您不能将auto_ptr
用于prect
,因为在指针上调用 delete 是未定义的(因为内存不是动态创建的)。如果将自定义删除程序传递给构造函数,则可以使用 shared_ptr
。如果在第二个模板参数中传入自定义删除程序,则可以使用 unique_ptr
。自定义删除程序只是显式调用析构函数,以便智能指针在代码超出范围时自动执行清理工作。
template <typename T>
struct placement_delete {
void operator () (T *t) const { t->~T(); }
};
char mem2[2][sizeof(CRectangle) alignas(CRectangle);
std::shared_ptr<CRectangle>
sprect(new (mem2[0]) CRectangle(2, 3), placement_delete<CRectangle>());
std::unique_ptr< CRectangle, placement_delete<CRectangle> >
uprect(new (mem2[1]) CRectangle(3, 4));
new
调用可能会引发std::bad_alloc
异常。由于它未被捕获,因此程序将在引发异常并产生错误结果后立即终止。如果要正常处理异常,可以使用try
和catch
块。
CRectangle *prect;
try {
prect = new (mem) CRectangle(3, 4);
} catch (std::bad_alloc) {
// do something about it?
abort();
}
对于学习来说,abort
是可以的。它可以让您练习捕获异常,但可以让您在分析由于abort
而留下的错误状态时快速查明问题的位置。(在 UNIX 上,这通常是一个核心文件。
那这个怎么样?
int main () {
CRectangle rect (3,4); // on stack
cout << "rect area: " << rect.area() << endl;
return 0;
}
或者,如果您必须有prect
:
int main () {
CRectangle rect (3,4); // still on stack
CRectangle * prect = ▭ // simple alias
cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
return 0;
}
但至少在你的简单代码中prect
是多余的。
通常,人们会期望看到一些new CRectangle()
(或从CRectangle
派生的类,分配给堆上)在创建时或以后分配给prect
。但目前还不清楚你打算做什么。但是既然在你的例子中prect
只是rect
的别名,为什么不直接使用rect
(我的第一段代码)呢?
使用堆:
int main () {
CRectangle* prect = new CRectangle(3,4); // using heap
// new will throw if out of memory, so no check for null pointer needed here
cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
delete prect; // free the memory - needed because it's not a stack object
return 0;
}
STL现在已经std::auto_ptr
被std::unique_ptr
(在C++11中)取代,正如Mooing Duck在评论中提到的那样。由于这个"智能指针"充当堆栈上的容器类,用于堆上的类的指针,因此它也将进行清理
int main () {
try
{
std::auto_ptr<CRectangle> prect(new CRectangle(3,4)); // using heap, via smart ptr
// new will throw if out of memory, so no check for null pointer needed here
cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
}
catch(exception& e)
{
cout << "Exception caught: " << e.what() << endl;
}
return 0;
}
auto_ptr
和unique_ptr
之间的主要区别在于它们的语义和所有权。您可以在维基百科页面上的智能指针上获得概述。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- Linux的Cpp上的计时器
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- 命名空间中具有.h和.cpp文件的类
- 内置函数可查看CPP中的成员变量
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- Cpp-Tuple使用带有变量的get
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 有充分的理由在h文件中使用include保护而不是cpp文件吗
- 如何通过cpp程序运行shell脚本
- 使用2个键的cpp-stl::优先级队列排序不正确
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- 如何在cpp文件之间切换窗口?在Qt中
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 我需要知道编译器如何在cpp中使用析构函数
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 打电话给没有标题的CPP课程
- CLION:调试CPP课程
- 初学者和CPP课程