Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么时候通过参考传递不是一个好主意?_C++_Memory Management - Fatal编程技术网

C++ 什么时候通过参考传递不是一个好主意?

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

这是一个我从未真正理解的内存分配问题

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()函数完成后将超出范围。这是否意味着我必须通过复制来传递参数?或者我可以通过引用来传递它,并以某种方式“侥幸逃脱”吗

基本上,我希望避免以下情况:

  • 我不想设置MonkeyFish的名称,只希望在函数终止时localname字符串的内存消失。(这似乎会非常糟糕。)
  • 如果可以的话,我不想复制字符串
  • 我宁愿不使用新的localname
  • 我应该使用什么样的原型和数据成员组合

    澄清:一些答案建议使用static关键字,以确保在MonkeyFish()结束时不会自动取消分配内存。由于此应用程序的最终目标是释放N条MonkeyFish(所有这些都必须有唯一的名称),因此这不是一个可行的选择。(是的,猴子鱼——一种易变的生物——经常改名,有时一天内会改名好几次。)


    编辑: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);”,如果您分配较小的值,它可能不会重新分配。(一)