c++中按值传递
Passing by value in C++
这里对象是按值传递的,我不明白程序的输出。
#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 operator
或destructor
中的任何一个,那么您可能也想定义其他两个。在这种情况下,您的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 constructor
和assignment 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;
}
};
- 何时应通过引用传递矢量参数而不是按值传递矢量参数?
- C++类 - 初始化列表 - 递归 - 按值传递
- 将函数参数完美转发到函数指针:按值传递呢?
- 棘手的按值传递和按引用递归问题传递
- 不同于按值传递和常量引用传递的程序集
- 按值传递变量与按引用传递变量具有相同的结果
- 为什么按值传递QStringView比引用常量更快?
- 获取 std::函数以推断按引用传递/按值传递
- 在函数中按值传递 unordered_map/unordered_set 是否有效? C++
- C++/11 auto 关键字是在更有效时推导参数进行按引用传递,还是始终按值传递?
- 使用 enable_if 在按值传递与按引用传递之间更改函数声明
- 防止在按值传递对象(继承)时进行切片
- 按值传递类和结构
- C++按引用传递还是按值传递?
- 为什么在按值返回时创建临时对象,而不是在按值传递给函数参数时创建临时对象
- 可移动但不可复制的对象:按值传递还是按引用传递?
- const-ref传递的模板化参数是否经过优化,以便在足够小时按值传递
- 在C++中指针是按值传递的吗
- shared_ptr构造函数参数是否应按值传递
- 使用 std::move 将参数传递给函数,如果该参数声明为按值传递或使用移动操作数 &&,是否有区别?