c++中按值传递

Passing by value in C++

本文关键字:按值传递 c++      更新时间:2023-10-16

这里对象是按值传递的,我不明白程序的输出。

#include <iostream>
using namespace std;
class Sample
{
public:
    int *ptr;
    Sample(int i)
    {
        ptr = new int(i);
    }
    ~Sample()
    {
        delete ptr;
    }
    void PrintVal()
    {
        cout << "The value is " << *ptr;
    }
};
void SomeFunc(Sample x)
{
    cout << "Say i am in someFunc " << endl;
}
int main()
{
    Sample s1= 10;
    SomeFunc(s1);
    s1.PrintVal();
}

您忘记编写一个复制构造函数。编译器会为你生成一个,它只是复制指针的值,而不是深度复制。因此,当你传递的参数被复制并销毁时,你的原始对象会在同一个指针上第二次调用delete,这是未定义的行为。

记住三规则
简而言之:
如果您需要定义copy-constructor, copy-assignment operatordestructor中的任何一个,那么您可能也想定义其他两个。在这种情况下,您的copy constructor应该看起来像这样:

Sample(const Sample& other)
      :ptr(new int(*other.ptr));
{
}

我想这里的输出应该是崩溃。

这里的问题是,当你通过值传递你的样本对象被复制。在你复制的对象中,你没有分配一个新的ptr。因此,当s1的副本被析构时,它将删除原始的s1。

在下面添加一个复制构造函数来获得你想要的行为。

Sample(const Sample &s)
{
    ptr = new int(*(s.ptr));
}

问题

编译器提供的类的默认复制构造函数只是复制指针,而不是指针指向的整数。现在你有两个指针指向同一个对象。当其中一个对象超出作用域时,另一个对象内的指针变为dangling pointer。试图访问悬空指针几乎总是会在运行时给您带来麻烦,例如使程序崩溃。

int main()
{
    Sample s1= 10;
    // copying by value here creates a local Sample object inside SomeFunc
    // which points to the same heap-allocated integer. After it goes out
    // of its scope(leaves this function), that memory is released. Then 
    // "ptr" in s1 becomes a dangling pointer.
    SomeFunc(s1);
    s1.PrintVal();
}
<<p> 解决方案/strong>

如果有任何类成员指针指向堆分配的缓冲区,则需要显式重载复制构造函数和赋值操作符=来深度复制这些指针成员,即分配新的内存并复制这些指针指向的数据。

问题是你的类包含一个指针。

真正的代码很少需要包含OWNED指针。它们通常被包装在一些实用程序类中(如智能指针或容器),或者更常见的是它们是简单对象。

你的代码应该是这样的:

class Sample
{
public:
    int val;    // No need to make it a pointer
    Sample(int i)
       : val(i)
    {}
    void PrintVal()
    {  cout << "The value is " << val;
    }
};

如果你需要一个动态分配的对象,那么它应该在一个智能指针中(假设你想要一个共享的资源,那么它看起来像这样)。

class Sample
{
public:
    std::shared_ptr<int>  ptr;
    Sample(int i)
        :ptr(new int(i))
    {}
    void PrintVal()
    {
        cout << "The value is " << *ptr;
    }
};

假设您正在编写自己的指针包装器(坏主意),但让我们假设它是为了练习指针。那你就得遵守三个原则。这是因为编译器生成的copy constructorassignment operator版本不会对OWNED RAW指针做正确的事情。OWNED RAW指针是您拥有的指针,因此负责删除。

这个问题有两个解决方案。将复制构造函数和赋值操作符设置为私有。这将使您的代码无法工作,所以我认为这不是您想要的。所以我们需要让它们发挥作用。由于上面的std::shared_ptr<>描述了共享的情况,这里我们将讨论非共享的复制情况。

class Sample
{
public:
    int *ptr;   // OWNED RAW POINTER
    Sample(int i)
       : ptr(new int(i))
    {}
    ~Sample()
    {
        delete ptr;
    }
    Simple(Simple const& copy)
        : ptr(new int (*(copy.ptr)))
    {}
    Simple& operator=(Simple rhs)    // Assignment uses the copy and swap idium.
    {                                // Notice the parameter is passed by value to get
        std::swap(ptr, rhs.ptr);     // an implicit copy using the copy constructor.
    }                                // Then we simply swap the pointers. The copy will be
                                     // destroyed with the old pointer.
    void PrintVal()
    {
        cout << "The value is " << *ptr;
    }
};