这是c++中实例化对象的正确方法
Which is the right way to instantiate objects in C++?
在c++中(我使用QT),我可以用两种方式创建QString类的实例:
方法1
QString str = "my string";
方法2
QString *str = new QString("my string");
我知道这与指针有关。所以我的问题是:
- 两者的区别是什么?
- 我应该坚持哪种方法?
- 何时使用方法1是正确的,何时使用方法2是正确的?
- 方法2中,我可以通过调用
delete str;
来销毁对象。使用方法1时,如何删除str
变量?
谢谢
-
主要是它们有不同的生命周期:在方法2中创建的对象将会任意长时间地存在,直到你调用delete;在方法1中,它将在堆栈上创建,并在函数调用(如果有的话)返回时销毁。次要方法2需要更多的工作,因为非琐碎的内存管理。
-
使用与所需生存期匹配的方法。如果方法1的生命周期足够好,就不要使用方法2,因为它会带来内存管理的开销。
如果你可以重构你的程序,这样你就可以使用方法1,同时也可以改进设计,这将更有效和优雅。
见2。以上。特别是,使用方法1并存储指向对象的指针并在其生命周期后访问它是一个陷阱。这对于方法2也是可能的,但是显式的销毁将程序员的注意力集中在它上(但仍然因为生命周期不是直接的,这是一个可能的陷阱)方法2的陷阱是忘记删除它导致内存泄漏(或删除它太早,并引用它如本段前面所述)
方法1中的对象将在函数返回时被自动删除。
这两者是完全不同的。
QString str("my string");
创建了一个生存期为自动管理的对象:该对象要么活到它的封闭作用域结束(如果它是一个局部变量),要么活到程序结束(如果它是一个全局变量)。
new QString("my string");
创建一个具有手动管理生存期的对象,也称为"动态对象"(并返回指向该对象的指针)。这意味着您负责管理对象的生命周期。从来都不是正确的做法,除非你正在编写一个库组件。
这就是c++哲学的核心:c++是编写库的语言。您拥有编写高质量、可重用组件的工具。当您这样做时,您将需要了解生命周期管理的复杂性。然而,在出现之前,您应该使用现有的库组件。当这样做时,您将发现几乎不需要执行任何手动管理。
使用动态容器(向量,字符串,映射等)来存储数据并构建自己的数据结构。如果需要修改调用者作用域中的对象,则通过引用传递参数。从简单的组件构建复杂的类。如果你真的必须有动态对象,通过unique_ptr<T>
或shared_ptr<T>
处理程序类来处理它们。
不要使用指针。很少使用new
,从不使用delete
。
(进一步提示:1)永远不要使用using namespace
,除非它用于ADL。2)除非你正在编写库组件,否则设计良好的类不应该有析构函数、复制构造函数或赋值操作符。如果它们确实存在,则将违规逻辑分解为单一责任库组件,然后参见2)。
当您使用第一种语法时,您正在创建名称为str
的对象,其类型为QString
,初始值为"my string"
。
在第二个声明中,您创建了类型为QString
的指针,其名称为str
。
指针不保存值,它们指向存储值的内存位置,两者的区别很大。
方法一将使用自动内存管理(当对象超出作用域时将被删除)。
方法二用于手动内存管理——在调用delete str;
之前它不会被删除如果您忘记删除它——这就造成了我们所说的内存泄漏!
通常方法一是最好的选择,除非你有理由使用指针。(减少出错的机会)
你可能会发现这很有用:为什么要使用指针?
区别在于方法一在堆栈上创建QString
,而方法二在自由存储上创建QString
。(注意,QString s = "hello";
与QString s("hello");
完全相同。)就像parapura rajkumar说的,当你能做的时候总是做1,当你不能做1的时候总是做2。
方法1有很多优点,其中最重要的是自动内存管理。该QString
占用的内存将在超出作用域时自动释放,因此您不需要做任何事情来释放其内存。方法2要求您在使用完delete
后使用它来释放内存,否则将发生内存泄漏。
另一个优点是,在堆栈上创建东西比在自由存储上创建东西快得多。
必须使用方法2的情况是当您需要该对象比您所在的作用域持续更长时间时。然后使用new
在自由存储中分配,这样它就会持续到调用delete
,然后传递指针。
何时使用方法1正确,何时使用方法2正确?
在本例中,何时可以使用指针并不明显。但是如果你创建自己的类,例如Images,它保存了很多数据,你想在函数或方法中传递那个类的对象,那么我建议你使用指向对象的指针,而不是对象本身。为什么?如果你传递一个指针到一个函数,你只传递了对象的内存地址(你复制了几个字节),但是如果你传递的是对象本身,那么你传递了大量的数据,这可能会减慢你的应用程序。
让我们看另一个例子:假设你有一个有三个参数的函数,函数体应该在函数结束时改变每个参数。如您所知,函数只能返回一个值,因此可以改变函数体中每个参数的一种方法是使用指针。
使用指针的原因有很多,在使用指针时应该小心。我建议你读一些关于这个主题的文章。
我希望你能理解其中的区别。关键概念是对象地址和对象本身的区别!
- 使用std::函数映射对象方法
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 按对象的特定方法按升序排列的C++优先级队列
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 从父类方法返回子类对象
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 为什么此派生对象无法访问基类的后递减方法?
- c++, 在子类中,如何在没有对象的情况下访问父类的方法?
- 正在调用shared_ptr对象方法
- 将方法转换为调用该方法的成员函子对象会导致崩溃
- 检查哪个对象调用了另一个对象的对象方法
- CPU 瓶颈;处理具有许多非静态对象的 3D 场景渲染的简单方法
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 没有取消引用/解包对象的标准方法?
- 使用 gmock c++ 在真实对象上调用方法
- 当我调用对象的方法时,对象的成员会发生变化
- 根据对象类调用不同的方法
- 如何在C++中循环访问未知对象方法?
- 使用动态实例化的对象填充矢量的快速方法
- 对类中的对象使用方法