C++ 什么时候通过参考传递不是一个好主意?
这是一个我从未真正理解的内存分配问题 void unleashMonkeyFish() { MonkeyFish * monkey_fish = new MonkeyFish(); std::string localname = "Wanda"; monkey_fish->setName(localname); monkey_fish->go(); } 孔雀鱼 { MonkeyFish*猴子鱼=新的MonkeyFish(); std::string localname=“Wanda”; 猴子鱼->设置名称(本地名称); 猴子鱼->走(); } 在上面的代码中,我在堆上创建了一个MonkeyFish对象,为其指定了一个名称,然后将其释放到世界上。假设已分配内存的所有权已转移到MonkeyFish对象本身,只有MonkeyFish本身才能决定何时死亡并删除自己 现在,当我在MonkeyFish类中定义“name”数据成员时,我可以选择以下选项之一: std::string name; std::string & name; void setName( const std::string & parameter_name ); void setName( const std::string parameter_name ); std::字符串名; std::字符串和名称; 在MonkeyFish类中定义setName()函数的原型时,可以选择以下选项之一: std::string name; std::string & name; void setName( const std::string & parameter_name ); void setName( const std::string parameter_name ); void setName(const std::string和参数_name); void setName(const std::string参数_name); 我希望能够最小化字符串副本。事实上,如果可以的话,我想完全消除它们。所以,看起来我应该通过引用传递参数…对吗 让我头疼的是,似乎我的localname变量在monkeyfish()函数完成后将超出范围。这是否意味着我必须通过复制来传递参数?或者我可以通过引用来传递它,并以某种方式“侥幸逃脱”吗 基本上,我希望避免以下情况:C++ 什么时候通过参考传递不是一个好主意?,c++,memory-management,C++,Memory Management,这是一个我从未真正理解的内存分配问题 void unleashMonkeyFish() { MonkeyFish * monkey_fish = new MonkeyFish(); std::string localname = "Wanda"; monkey_fish->setName(localname); monkey_fish->go(); } 孔雀鱼 { MonkeyFish*猴子鱼=新的MonkeyFish(); std::st
编辑:Greg Hewgil指出,将name变量存储为引用是非法的,因为它不是在构造函数中设置的。我将错误保留在问题中,因为我认为我的错误(以及Greg的更正)可能对第一次看到这个问题的人有用。您可以将MonkeyFish中的字符串设置为静态,但我认为这并没有真正的帮助(可能会非常糟糕,具体取决于实现方式)
我已经从高级语言(如C#,Java)中“下移”,最近也遇到了同样的问题。我假设通常唯一的选择是复制字符串。如果使用临时变量分配名称(如示例代码中所示),则最终必须将字符串复制到MonkeyFish对象,以避免临时字符串对象在您身上结束作用域 正如Andrew Flanagan提到的,可以通过使用局部静态变量或常量来避免字符串复制
假设这不是一个选项,您至少可以将字符串副本的数量减少到正好一个。将字符串作为引用指针传递给setName(),然后在setName()函数内部执行复制。通过这种方式,您可以确保复制只执行一次。为了澄清术语,您已经从堆(使用new)和堆栈上的localname创建了MonkeyFish 好的,所以存储对一个对象的引用是完全合法的,但显然您必须知道该对象的范围。通过引用传递字符串,然后复制到类成员变量要容易得多。除非字符串非常大,或者您经常执行此操作(我的意思是很多,很多),否则就没有必要担心 你能解释一下为什么你不想复制这个字符串吗 编辑 另一种方法是创建MonkeyName对象池。每个MonkeyName存储一个指向字符串的指针。然后从池中请求一个新的MonkeyName(在内部字符串*上设置名称)。现在通过引用将其传递到类中,并执行直接指针交换。当然,传入的MonkayName对象会发生更改,但如果它直接返回到池中,则不会有什么不同。唯一的开销是从池中获取MonkeyName时名称的实际设置
。。。希望这有点道理:)如果您使用以下方法声明:
void setName( const std::string & parameter_name );
std::string name;
然后您还将使用成员声明:
void setName( const std::string & parameter_name );
std::string name;
以及setName
正文中的赋值:
name = parameter_name;
您不能将名称
成员声明为引用,因为必须在对象构造函数中初始化引用成员(这意味着您无法在集合名称
中对其进行设置)
最后,您的
std::string
实现可能会使用引用计数字符串,因此在赋值中不会复制实际字符串数据。如果您非常关心性能,那么最好熟悉正在使用的STL实现。一种方法是使用字符串
std::string name;
作为对象的数据成员。然后,在MonkeyFish函数中,像您所做的那样创建一个字符串,并像您所展示的那样通过引用传递它
void setName( const std::string & parameter_name ) {
name = parameter_name;
}
它将执行您想要的操作—创建一个副本以将字符串复制到数据成员中。如果您分配另一个字符串,它就不需要在内部重新分配新的缓冲区。可能,分配一个新字符串只会复制几个字节。string具有保留字节的功能。因此,您可以在构造函数中调用“name.reserve(25);”,如果您分配较小的值,它可能不会重新分配。(一)