这是我从未真正理解的内存分配问题。
无效unleashMonkeyFish()
{
MonkeyFish * monkey_fish =新的MonkeyFish();
std::string localname =“Wanda”;
monkey_fish-> setName(localname);
monkey_fish-> go();
}
在上面的代码中,我在堆上创建了MonkeyFish对象,为其分配了名称,然后将其释放给世界。假设已分配内存的所有权已转移到MonkeyFish对象本身-只有MonkeyFish本身将决定何时消亡和删除自身。
现在,当我在MonkeyFish类中定义“名称”数据成员时,可以选择以下选项之一:
std::string名称;
std::string&name;
当我在MonkeyFish类中为setName()函数定义原型(prototype)时,可以选择以下选项之一:
无效setName(const std::string&parameter_name);
void setName(const std::string parameter_name);
我希望能够最小化字符串拷贝。实际上,如果可以的话,我想完全消除它们。因此,似乎我应该通过引用传递参数...对吗?
令我感到困扰的是,一旦unleashMonkeyFish()函数完成,我的localname变量似乎将超出范围。这是否意味着我被强制通过拷贝传递参数?还是我可以通过引用传递它并以某种方式“摆脱它”?
基本上,我想避免这些情况:
我应该使用哪种原型(prototype)和数据成员组合?
澄清:建议使用static关键字的几个答案,以确保在unleashMonkeyFish()结束时不会自动取消分配内存。由于此应用程序的最终目标是释放N个MonkeyFish(所有这些名称都必须具有唯一的名称),因此这不是一个可行的选择。 (是的,MonkeyFish-善变的生物-经常在一天中的某些时候多次更改其名称。)
编辑:Greg Hewgil指出,将名称变量存储为引用是非法的,因为未在构造函数中进行设置。我将错误原样留在问题中,因为我认为我的错误(以及Greg的更正)对于第一次看到此问题的人可能有用。
最佳答案
一种方法是让您的琴弦
std::string name;
作为对象的数据成员。然后,在unleashMonkeyFish函数中像您一样创建一个字符串,并像显示的那样通过引用传递它
void setName( const std::string & parameter_name ) {
name = parameter_name;
}
它将执行您想要的操作-创建一个拷贝以将该字符串复制到您的数据成员中。如果您分配了另一个字符串,就好像它不必在内部重新分配新的缓冲区一样。分配一个新字符串可能只复制了几个字节。 std::string具有保留字节的功能。因此,您可以调用“name.reserve(25);”。在构造函数中,如果分配较小的内容,则可能不会重新分配。 (我已经做过测试,如果您从另一个std::string进行分配,看起来GCC总是重新分配,但是如果您从c字符串进行分配,则不会重新分配。They say他们有一个写时复制字符串,这可以解释该行为)。
您在unleashMonkeyFish函数中创建的字符串将自动释放其分配的资源。那是这些对象的关键特征-他们管理自己的东西。类具有析构函数,一旦对象死亡,它们便可以释放分配的资源,std::string也是如此。我认为,您不必担心在函数中使用本地的std::string。无论如何,它不会对您的表现产生任何明显的影响。一些std::string实现(msvc++ afaik)进行了小缓冲区优化:为了达到一些小限制,它们将字符保留在嵌入式缓冲区中,而不是从堆中分配。
编辑:
事实证明,对于具有有效
swap
实现(恒定时间)的类,有一种更好的方法:void setName(std::string parameter_name) {
name.swap(parameter_name);
}
之所以更好,是因为现在调用者知道该参数正在被复制。现在,编译器可以轻松地应用返回值优化和类似的优化。考虑这种情况,例如
obj.setName("Mr. " + things.getName());
如果您让
setName
进行引用,则在参数中创建的临时文件将绑定(bind)到该引用,并在setName
中将其复制,然后在返回之后,该临时文件将被销毁-无论如何,这是一个一次性产品。这只是次优的,因为可以使用临时本身而不是其拷贝。使参数不具有引用将使调用者看到该参数无论如何都被复制,并使优化器的工作更加容易-因为不必内联调用即可看到该参数是否仍被复制。有关进一步的说明,请阅读精美的文章
BoostCon09/Rvalue-References
。关于c++ - 什么时候通过引用不是一个好主意?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/589076/