首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >铁锈与C++:从函数返回对象

铁锈与C++:从函数返回对象
EN

Stack Overflow用户
提问于 2020-07-19 12:17:16
回答 1查看 716关注 0票数 2

我对Rust很陌生,并试图了解从函数返回对象时所有权是如何传递的。在下面的基于引用的实现中,由于引用没有所有权,所以当"s“超出范围时,它会被删除和释放。

代码语言:javascript
复制
fn dangle() -> &String { // dangle returns a reference to a String

    let s = String::from("hello"); // s is a new String

    &s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
  // Danger!

这是通过不返回引用来修正的:

代码语言:javascript
复制
fn no_dangle() -> String {
    let s = String::from("hello");

    s
}

现在,我正试图用C++实现来理解这一点,如下所示:

代码语言:javascript
复制
std::string no_dangle() {
    std::string s("hello world");
    return s;
}

根据我的理解,在C++中,当"s“从函数返回时,使用复制构造函数创建另一个副本,函数get deallocated.This中创建的"s”表示,创建了两个在内存方面不太透明的对象。

我的问题:

  1. In Rust,当函数返回"s“时,没有额外的对象是created.Only,在堆中分配的所有权是returned.The原始对象,保持same.Is正确吗?

在smart-pointer?中,您可以通过返回对象以及Rust中的指针(智能指针或原始指针).But从函数返回"things“,唯一返回"things”的是上面的内容,这与接近返回一个的C++相比

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-19 12:42:02

铁锈和C++都是值类型的语言,因此除非明确要求,否则不会在堆上分配对象/结构。因此,在给定的两种情况下,都不存在堆上分配的字符串对象/结构。在这两种语言中,字符串使用存储在堆上的动态分配的支持缓冲区,但这是一个重要的区别。

因此,在铁锈中,如果按值返回,则对象将被移动,这通常等同于直接的memcpy,因为锈蚀结构不允许具有自定义移动逻辑,而且克隆必须是显式的。该memcopy将指针复制到备份存储,因此字符串对象可能在不同的内存中,但备份缓冲区保持不变。

在C++中,对象可以具有非平凡的副本和(在C++11和更高版本中)移动构造函数。因此,如果这不是返回一个命名值,那么就必须调用复制或移动构造函数。但是,对于函数返回的具体情况,复制省略规则起作用。这意味着(在C++17和以后的一些简单情况下),如果对象是在返回语句中初始化的,或者来自具有自动存储持续时间的位置,则编译器不会调用复制/移动构造函数,而是将对象直接构造为调用方在最初创建返回对象时提供的存储,这意味着在返回点不需要复制或移动。这就是所谓的返回值优化。

如果在C++11或更高版本中,您要返回一个非对象初始化或具有自动存储持续时间的命名值(或者在那些情况下,除了C++17中的对象初始化及以后的对象初始化外),例如调用另一个函数的结果,则将调用移动构造函数,在这种情况下,只需将指针复制到后备存储,并清除旧字符串中的指针。在这种情况下,这种行为就像生锈一样。但是,如果该类型有一个更复杂的迁移构造函数,则它可以执行任何移动操作。

最后,在C++98中,如果要返回一个非对象初始化值或具有自动存储持续时间的命名值,则将调用复制构造函数,将备份存储复制到一个新的备份存储中,并且返回该备份存储。导致一个指向不同内存的新字符串。当作用域结束时,旧内存将由析构函数释放。

此外,C++实现可以使用小字符串优化,其中小字符串直接存储在string对象中。在这种情况下,将没有后备存储,即使对象被移动,也必须复制字符串。

最后要注意的一点是,在使用C++11之前,std::string实现通常使用引用计数备份存储。在这种情况下,副本将增加备份存储上的引用计数,析构函数将减少其增量,但不会释放,因为仍然存在对存储的引用。在这种情况下,生成的字符串仍然指向原始备份存储,但代价是比移动更昂贵的进程。随着move构造函数的引入,这种情况变得不那么常见了。

为了快速回答第二个问题,铁锈还允许返回智能指针、指针和引用,但是锈迹借用检查器将阻止返回对象本地对象的引用,因为它们没有足够的生存期。这并不妨碍返回参数和全局值(例如字符串文本或线程局部变量)的引用,因为它们的生存期比函数长。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62980187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档