当前位置:  开发笔记 > 编程语言 > 正文

C++对象实例化

如何解决《C++对象实例化》经验,为你挑选了6个好方法。

我是一名试图理解C++的C程序员.许多教程使用片段演示对象实例化,例如:

Dog* sparky = new Dog();

这暗示你以后会这样做:

delete sparky;

这是有道理的.现在,在不需要动态内存分配的情况下,有没有理由使用上面的代替

Dog sparky;

一旦sparky超出范围,让析构函数被调用?

谢谢!



1> jalf..:

相反,您应该总是更喜欢堆栈分配,在一定程度上,您的用户代码中永远不应该有新的/删除.

正如您所说,当变量在堆栈上声明时,它的析构函数会在超出范围时自动调用,这是跟踪资源生命周期和避免泄漏的主要工具.

因此,通常,每次需要分配资源时,无论是内存(通过调用new),文件句柄,套接字还是其他任何东西,都将它包装在构造函数获取资源的类中,析构函数将其释放.然后,您可以在堆栈上创建该类型的对象,并确保在资源超出范围时释放资源.这样您就不必在任何地方跟踪新的/删除对,以确保避免内存泄漏.

这个成语最常见的名字是RAII

还要研究智能指针类,它们用于在极少数情况下包装结果指针,当您必须在专用RAII对象外部分配新内容时.您将指针传递给智能指针,然后智能指针跟踪其生命周期,例如通过引用计数,并在最后一个引用超出范围时调用析构函数.标准库具有std::unique_ptr简单的基于范围的管理,并且std::shared_ptr引用计数来实现共享所有权.

许多教程使用片段演示对象实例化,例如...

所以你发现的是大多数教程很糟糕.;)大多数教程教你糟糕的C++实践,包括调用new/delete来创建变量(如果没有必要),并让你很难跟踪你的分配生命周期.


格雷格:当然可以.但正如你所说,一个边缘案例.通常,最好避免使用指针.但他们在语言中是有原因的,不可否认.:) dviljoen:如果对象很大,则将其包装在RAII对象中,该对象可以在堆栈上分配,并包含指向堆分配数据的指针.
@dviljoen:不,我不是.C++编译器不会不必要地膨胀对象.您将看到的最糟糕的情况通常是它会四舍五入到最接近的四个字节的倍数.通常,包含指针的类将占用与指针本身一样多的空间,因此在堆栈使用中不需要任何费用.
这是一个正确的答案,但我永远不会养成在堆栈上创建对象的习惯的原因是因为它永远不会完全明显该对象有多大.你只是要求堆栈溢出异常.

2> UniversE..:

虽然堆栈上的东西在分配和自动释放方面可能是一个优势,但它有一些缺点.

    您可能不希望在堆栈上分配大型对象.

    动态调度!考虑以下代码:

#include 

class A {
public:
  virtual void f();
  virtual ~A() {}
};

class B : public A {
public:
  virtual void f();
};

void A::f() {cout << "A";}
void B::f() {cout << "B";}

int main(void) {
  A *a = new B();
  a->f();
  delete a;
  return 0;
}

这将打印"B".现在让我们看看使用Stack时会发生什么:

int main(void) {
  A a = B();
  a.f();
  return 0;
}

这将打印"A",对于熟悉Java或其他面向对象语言的人来说可能不太直观.原因是您没有指向B更长实例的指针.而是B创建一个实例并将其复制到a类型的变量中A.

有些事情可能会不直观地发生,特别是当你不熟悉C++时.在C中你有你的指针就是这样.你知道如何使用它们,它们总是一样.在C++中,情况并非如此.试想会发生什么,当你在这个例子中使用作为一个方法的参数-事情变得更复杂,但它使一个巨大的区别,如果a是类型A或者A*甚至A&(呼叫通过引用).许多组合都是可能的,它们的行为都不同.


-1:人们无法理解值语义和多态性需要引用/指针(避免对象切片)这一简单事实并不构成语言的任何问题.c ++的力量不应该被认为是一个缺点,因为有些人不能学习它的基本规则.

3> PierreBdR..:

好吧,使用指针的原因与在使用malloc分配的C中使用指针的原因完全相同:如果你希望你的对象比你的变量活得更久!

如果可以避免使用新操作员,甚至强烈建议不要使用它.特别是如果你使用例外.通常,让编译器释放您的对象会更安全.



4> Mark Ransom..:

我从那些没有得到&address-of运算符的人那里看到了这种反模式.如果他们需要使用指针调用函数,他们将始终在堆上进行分配,以便获得指针.

void FeedTheDog(Dog* hungryDog);

Dog* badDog = new Dog;
FeedTheDog(badDog);
delete badDog;

Dog goodDog;
FeedTheDog(&goodDog);



5> Naveen..:

将堆视为一个非常重要的房地产,并非常明智地使用它.基本的经验法则是使用堆栈尽可能和使用堆每当有没有其他办法.通过在堆栈上分配对象,您可以获得许多好处,例如:

(1).如果出现异常,您无需担心堆栈展开

(2).您不必担心由堆管理器分配的空间超出所需的内存碎片.



6> Roddy..:

我担心的唯一原因是Dog现在被分配在堆栈上,而不是堆.因此,如果Dog的大小为兆字节,则可能会出现问题,

如果确实需要使用新的/删除路由,请注意例外情况.因此,您应该使用auto_ptr或其中一种boost智能指针类型来管理对象的生命周期.

推荐阅读
保佑欣疼你的芯疼
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有