在C ++中传递值

时间:2011-08-07 13:33:44

标签: c++ pass-by-value

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

#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();
}

4 个答案:

答案 0 :(得分:8)

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

请记住 Rule of Three 简而言之:
如果您需要定义copy-constructorcopy-assignment operatordestructor,则可能还需要定义其他两个。在这种情况下,您的copy constructor应如下所示:

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

答案 1 :(得分:2)

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

这里的问题是,当您传递值时,您的Sample对象将被复制。在您复制的对象中,您没有分配新的ptr。因此,当s1的副本被破坏时,它将删除原始的s1。

在下面添加一个复制构造函数以获得所需的行为。

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

答案 2 :(得分:1)

<强>问题

编译器提供的类中的默认复制构造函数只是复制指针而不是指针指向的整数。所以现在你有两个指针指向一个对象。当其中一个对象超出范围时,另一个对象内的指针变为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();
}

<强>解决方案

如果有任何类成员指针指向堆分配的缓冲区,则需要明确地重载复制构造函数和赋值operator =以深度复制这些指针成员,即分配新内存并复制这些指针所指向的数据。

答案 3 :(得分:0)

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

实际代码很少需要包含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&lt;&gt;覆盖在这里,我们将介绍制作副本的非共享案例。

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;
    }
};