有关值传递可能产生的问题与解决(C++)

本文探讨了C++中值传递可能导致的构造与析构开销以及对象切割问题。值传递时,传递一个Student对象会引发4次构造和析构,而引用传递则避免了对象复制,提高了效率。此外,值传递可能导致对象切割,使得子类特有的信息丢失。通过引用或指针传递可以解决这个问题,推荐尽量使用引用传递,尤其对于复杂类型,内置类型和STL元素例外。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0、通篇示例代码

class Person{
public:
    Person();
    virtual ~Person();
    void Speak(){std::cout << name;}
    ...
private:
    std::string name;
    ...
};

class Student: public Person{
public:
    Student();
    ~Student();
    void Speak(){std::cout << name;}
    ...
private:
    std::string name;
    ...
}

1、有关值传递的过程中构造与析构过程

现有以下代码:

bool validateStudent(Student s);
Student Jack;
bool JackIsOk = validateStudent(Jack);

以上函数validateStudent需要一个Student的实参(值传递),并返回它是否有效。
在函数被调用时,以Jack为蓝本将s初始化。且同样的在函数返回时,s会被销毁。
但是在整个过程中,Student中有一个string对象,每次构造一个Student对象也就会构造1个string对象。此外Student对象继承Person对象,所以每次构造Student对象也必须构造出一个Person对象,一个Person又有一个String对象。最终结果是,以值传递方式传递一个Student对象会导致调用一次Student copy构造函数、一次Person copy构造函数、两次String copy构造函数。因此,以值传递方式传递一个Student对象,总的成本是“4次构造函数和4次析构函数”。

解决办法:

bool validateStudent(const Student& s);

采用引用传递方法非常高效:没有任何构造函数或析构函数被调用,因为没有任何新对象被创建。修订后的const是重要的。原来通过值传递时,接收的是一个Student参数,因此调用者知道他们受到保护,validateStudent只能对其副本做修改。现在以引用方式传递,将其生命为const是必要的,因为需要保证函数不会改变传入的Student。

2、可能存在的对象切割(slicing)问题

现有以下代码:

void smoebodyspeak(Person p)
{
	p.Speak();
}
int main()
{
	Student rose;
	somebodyspeak(rose);
}

很明显以上代码是以值传递方式将对象传递到somebodyspeak中,但参数p会被构造成一个Person对象,从而造成rose"之所以是Student对象"的所有特化信息被切除。somebodyspeak只会将传递过来的对象看作是Person对象,因为他的类型就是Person。因此在somebodyspeak内调用的总是Person::Speak,绝不会是Student::Speak

解决办法:

void smoebodyspeak(const Person& p)
{
	p.Speak();
}

通过引用传递就会实现传进来的是什么类型,p就会表现出那种类型。
其实引用传递,往往是以指针实现出来,因此引用传递通常意味着真正传递的是指针。

注意:
1、尽量以引用传递代替值传递。前者通常比较高效,并且可以避免切割问题。
2、以上规则并不使用与内置类型,以及STL的迭代器和函数对象。对他们而言往往是值传递比较适当。

[1]有关书籍:Effective C++中文版(第三版)–Scott Meyers(著)与侯捷(译)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值