c++ - 在 C++ 中实例化的首选方式是什么?

标签 c++

我还是 C++ 新手。我发现你可以用两种不同的方式在 C++ 中实例化一个实例:

// First way
Foo foo;
foo.do_something();

// Second way
Baz *baz = new Baz();
baz->do_something();

两者我看不出有什么大的区别,并且可以访问属性。 C++ 中哪种方式是首选?或者,如果问题不相关,我们什么时候使用哪个以及两者之间有什么区别?

感谢您的帮助。

最佳答案

这个问题不相关:没有首选的方法,它们只是做不同的事情。

C++ 都有值语义和引用语义。当函数请求时,这意味着您将向其传递整个对象的拷贝。当它请求引用(或指针)时,您只需向它传递该对象的内存地址。两种语义都是可转换的,也就是说,如果获得一个值,则可以获得引用或指向它的指针,然后使用它,而当获得引用时,您可以获取它的值并使用它。举个例子:

void foo(int bar) { bar = 4; }
void foo(int* bar) { *bar = 4; }
void test()
{
    int someNumber = 3;
    foo(someNumber); // calls foo(int)
    std::cout << someNumber << std::endl; 
    // printed 3: someNumber was not modified because of value semantics,
    // as we passed a copy of someNumber to foo, changes were not repercuted
    // to our local version

    foo(&someNumber); // calls foo(int*)
    std::cout << someNumber << std::endl;
    // printed 4: someNumber was modified, because passing a pointer lets people
    // change the pointed value
}

创建对值的引用(即获取值的指针)是非常非常常见的事情,因为引用非常有用,特别是对于复杂类型,其中传递引用显着避免了可能昂贵的复制操作.

现在,您将使用的实例化方式取决于您想要实现的目标。您展示的第一种方式使用自动存储;第二个使用堆。

主要区别在于,自动存储上的对象会随着它们存在的范围(范围大致定义为一对匹配的大括号)而被销毁。这意味着您绝不能从常规函数返回对在自动存储上分配的对象的引用,因为当您的函数返回时,该对象将被销毁,并且其内存空间可能会在以后的任何时候被重用。你的程序。 (在自动存储上分配的对象也有性能优势,因为您的操作系统不必查找可能放置新对象的位置。)

另一方面,堆上的对象将继续存在,直到它们被 delete 语句显式删除为止。这会产生与操作系统和平台相关的性能开销,因为操作系统需要查找程序的内存以找到足够大的未占用位置来创建对象。由于 C++ 不进行垃圾收集,因此必须指示您的程序何时删除堆上的对象。否则会导致泄漏:堆上的对象不再被任何变量引用,但未显式删除,因此将一直存在,直到程序退出。

所以这是一个权衡的问题。要么您接受您的值不能比您的函数更长久,要么您接受您必须在某个时候自己显式删除它。除此之外,两种分配对象的方式都是有效的并且按预期工作。

供进一步引用,自动存储意味着该对象将分配到其父范围所在的位置。例如,如果您有一个包含 std::string 的类 Foo,则 std::string 将存在于您分配 Foo对象。

class Foo
{
public:
    // in this context, automatic storage refers to wherever Foo will be allocated
    std::string a;
};

int foo()
{
    // in this context, automatic storage refers to your program's stack
    Foo bar; // 'bar' is on the stack, so 'a' is on the stack
    Foo* baz = new Foo; // 'baz' is on the heap, so 'a' is on the heap too
    // but still, in both cases 'a' will be deleted once the holding object
    // is destroyed
}

如上所述,您不能直接泄漏驻留在自动存储上的对象,但一旦创建它们的作用域被销毁,您就无法使用它们。例如:

int* foo()
{
    int a; // cannot be leaked: automatically managed by the function scope
    return &a; // BAD: a doesn't exist anymore
}

int* foo()
{
    int* a = new int; // can be leaked
    return a; // NOT AS BAD: now the pointer points to somewhere valid,
              // but you eventually need to call `delete a` to release the memory
}

关于c++ - 在 C++ 中实例化的首选方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5320449/

相关文章:

c++ - 发布安全、宽松的内存模型和 memcpy

c++ - 如何在另一个函数中使用这些变量?

c++ - 奇怪的基准测试结果

c++ - 如果我们有基*类,如何访问派生模板类的成员函数

c++ - 将 std::string 传递给 OpenCL 内核

c++ - STL 迭代器 - 为什么代码分析工具会报错?

c++ - 人们是否能够使用自己的实现来劫持已编译的库?

c++ - IOStream 库有哪些重要的替代方案? (除了 cstdio)

c++ - 在嵌套命名空间中转发声明

c++ - ostream .open 函数不存在 (C++)