标签: ownership-semantics

聪明的指针:或谁拥有你的宝贝?

C++完全是关于内存所有权
Aka" Ownership Semantics "

一块动态分配的内存的所有者负责释放该内存.所以这个问题真的变成了拥有记忆的人.

在C++中,所有权都是由RAW指针包含在内部的类型记录的,因此在一个好的(IMO)C++程序中,很少见[RARE并非永远]看到RAW指针传递(因为RAW指针没有推断的所有权因此我们不能告诉谁拥有记忆,因此如果没有仔细阅读文件,你无法分辨谁负责所有权).

相反,很少看到RAW指针存储在类中,每个RAW指针都存储在自己的SMART指针包装器中.(注意:如果你没有一个对象,你不应该存储它,因为你不知道什么时候它会超出范围并被销毁.)

所以问题是:

  • 人们遇到什么类型的所有权语义?
  • 使用哪些标准类来实现这些语义?
  • 你认为它们在哪些情况下有用?

让我们为每个答案保留一种语义所有权,这样他们就可以单独上下投票

摘要:

从概念上讲,智能指针很简单,而且简单易用.我已经看过许多尝试过的实现,但总是以某种方式打破它们,这对于随意使用和示例来说并不明显.因此,我建议始终使用经过良好测试的"智能指针",而不是自己动手.std :: auto_ptr或其中一个提升智能指针似乎涵盖了我的所有需求.

的std :: auto_ptr的<T>:

单身人士拥有该物品.
但允许转让所有权.

用法:
======
这允许您定义显示所有权显式转移的接口.

升压:: scoped_ptr的<T>

单身人士拥有该物品.
不允许转让所有权.

用法:
======
用于显示明确的所有权.
对象将被析构函数或显式重置时销毁.

boost :: shared_ptr <T>(std :: tr1 :: shared_ptr <T>)

多个所有权.
这是一个简单的引用计数指针.当引用计数达到零时,对象被销毁.

用法:
======
当对象可以有多个owers,其生命周期无法在编译时确定.

升压::的weak_ptr <T>

与shared_ptr <T>一起使用.
在指针循环可能发生的情况下.

用法:
======
用于在仅循环维护共享引用计数时停止保留对象的周期.

c++ memory-management smart-pointers ownership-semantics

113
推荐指数
3
解决办法
5万
查看次数

对于像所有权语义这样的原始指针返回unique_ptr的不良做法?

我编写了一个静态工厂方法,它返回从另一个数据对象填充的新Foobar对象.我最近一直沉迷于所有权语义,我想知道我是否通过这种工厂方法返回一个正确的信息unique_ptr.

class Foobar {
public:
    static unique_ptr<Foobar> factory(DataObject data);
}
Run Code Online (Sandbox Code Playgroud)

我的目的是告诉客户端代码他们拥有指针.没有智能指针,我只会回来Foobar*.但是,我想强制删除这个内存以避免潜在的错误,所以这unique_ptr似乎是一个合适的解决方案.如果客户端想要延长指针的生命周期,他们只需在调用.release()后调用unique_ptr.

Foobar* myFoo = Foobar::factory(data).release();
Run Code Online (Sandbox Code Playgroud)

我的问题分为两部分:

  1. 这种方法是否传达了正确的所有权语义?
  2. 返回unique_ptr而不是原始指针这是一个"坏习惯" 吗?

c++ smart-pointers ownership-semantics unique-ptr

49
推荐指数
3
解决办法
2万
查看次数

Rust如何移动不可复制的堆栈变量?

这里记录了Rust的移动语义的一个很好的例子:在Rust By Example网站上的Rust Move Semantics.

我对两个案例都有基本的了解.第一个是原语如何具有新别名,原始仍然可以使用,因为最终结果是看到i32利用Copy特征的副本.这对我来说很有意义.

此外,由于许多好的理由,第二个示例在具有多个引用i32堆上的别名方面是有意义的.Rust强制执行所有权规则,因此现在无法使用原始别名创建新绑定.这有助于防止数据争用,双重释放等.

但似乎还有第三个案例没有被谈到.Rust如何实现不实现Copy特征的堆栈分配结构的移动? 使用以下代码对此进行说明:

#[derive(Debug)]
struct Employee{
    age: i32,
}

fn do_something(m: Employee){
    println!("{:?}", m);
}

fn main() {
    let x = Employee {
        age: 25,
    };

    do_something(x);

    //compiler error below because x has moved
    do_something(x);
}
Run Code Online (Sandbox Code Playgroud)

我知道:在上面的例子中,Rust会Employee在堆栈上分配.上述结构不实现Copy特征,因此在分配给新别名时不会被复制.这对我来说非常混乱,因为如果Employee结构被分配在堆栈上并且也没有实现Copy特性在哪里/如何移动?它是否在物理上移动到do_something()堆栈框架?

在解释这个难题时,我们对任何帮助表示赞赏.

ownership-semantics move-semantics rust

14
推荐指数
1
解决办法
830
查看次数

如何调用在盒装特征对象上消耗self的方法?

我有一个实现的草图:

trait Listener {
    fn some_action(&mut self);
    fn commit(self);
}

struct FooListener {}

impl Listener for FooListener {
    fn some_action(&mut self) {
        println!("{:?}", "Action!!");
    }

    fn commit(self) {
        println!("{:?}", "Commit");
    }
}

struct Transaction {
    listeners: Vec<Box<Listener>>,
}

impl Transaction {
    fn commit(self) {
        // How would I consume the listeners and call commit() on each of them?
    }
}

fn listener() {
    let transaction = Transaction {
        listeners: vec![Box::new(FooListener {})],
    };
    transaction.commit();
}
Run Code Online (Sandbox Code Playgroud)

我可以Transaction在它们上面使用侦听器,当事务发生时会调用侦听器.既然Listener是特质,我会存储一个Vec<Box<Listener>> …

ownership-semantics rust

10
推荐指数
2
解决办法
1330
查看次数

如何重用我已移出值的框?

我有一些不可复制的类型和一个消耗和(可能)生成它的函数:

type Foo = Vec<u8>;

fn quux(_: Foo) -> Option<Foo> {
    Some(Vec::new())
}
Run Code Online (Sandbox Code Playgroud)

现在考虑一种在概念上非常类似的类型Box:

struct NotBox<T> {
    contents: T
}
Run Code Online (Sandbox Code Playgroud)

我们可以编写一个临时移出内容的函数,NotBox并在返回之前放回一些东西:

fn bar(mut notbox: NotBox<Foo>) -> Option<NotBox<Foo>> {
    let foo = notbox.contents; // now `notbox` is "empty"
    match quux(foo) {
        Some(new_foo) => {
            notbox.contents = new_foo; // we put something back in
            Some(notbox)
        }
        None => None
    }
}
Run Code Online (Sandbox Code Playgroud)

我想编写一个与Boxes 一起使用的类似函数,但编译器不喜欢它:

fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
    let foo = *abox; // now …
Run Code Online (Sandbox Code Playgroud)

boxing ownership-semantics move-semantics rust

9
推荐指数
2
解决办法
1577
查看次数

在Delphi中明确表达所有权

我主要是C++程序员,我已经习惯了具有类似于类模板std::unique_ptr,std::shared_ptr表达我的对象的所有权等.Delphi的标准库中是否有类似的东西?在编写代码时,是否有任何表达对象所有权的最佳实践?

编辑:由于C++ 11成为标准,有两个轻量级助手类,std::shared_ptrstd::unique_ptr.

如果我创建一个类型的变量std::shared_ptr<int>,它表示一个指向具有共享所有权的int的指针:引擎计数引用,当引用计数达到零时,指针将自动释放.这种类型表示一种"共享所有权",其中许多对象共同负责在完成资源时销毁资源.

相反,std::unique_ptr表达单一所有权.当unique_ptr超出范围时,将自动释放资源.std :: unique_ptr无法复制:一次只能有一个对象拥有此资源,并且只有一个对象负责清理对象.

将这些轻量级类与一个指向int的裸指针进行对比,它可以表示共享所有权,唯一所有权,或者它可以只是对其他地方的对象的引用!类型告诉你什么.

我的问题是:由于Delphi支持对对象的引用,是否有任何机制可以明确说明"我是这个对象的唯一所有者,当我完成它时,我会释放它",vs"我只是保留一个引用此对象以便与它进行交互,但是其他人会清理它"vs"我与许多其他对象共享此对象,并且最后拥有它的任何人都可以清理它."

我知道Collections.Generics有不同的集合,比如TListvs TObjectList,其中TObjectList将释放存储在其中的成员,但TList不会.你可以说TObjectList"拥有"它的元素,而TList则没有.这是我的问题的本质,真的.在设计我自己的课程时,有没有办法在语言中直接表达这些所有权问题?或者是否有开发人员常见的最佳实践/命名约定?

c++ delphi ownership-semantics delphi-xe3

8
推荐指数
1
解决办法
436
查看次数

在析构函数c ++中访问所有者

假设有一个对象A拥有一个对象B via std::unique_ptr<B>.进一步B保持对A的原始指针(弱)引用.然后A的析构函数将调用B的析构函数,因为它拥有它.

在B的析构函数中访问A的安全方法是什么?(因为我们也可能在A的析构函数中).

一种安全的方法是在A的析构函数中明确重置对B的强引用,以便以可预测的方式销毁B,但一般的最佳实践是什么?

c++ smart-pointers ownership-semantics

8
推荐指数
1
解决办法
351
查看次数

通用函数接受&str或移动String而不复制

我想编写一个通用函数,它接受任何类型的字符串(&str/ String)以方便调用者.

函数内部需要a String,所以如果调用者调用函数,我也想避免不必要的重新分配String.

foo("borrowed");
foo(format!("owned"));
Run Code Online (Sandbox Code Playgroud)

接受参考我知道我可以使用foo<S: AsRef<str>>(s: S),但另一种方式呢?

我认为基于的泛型参数ToOwned可能有用(适用于&str,我假设它是无操作String),但我无法弄清楚确切的语法.

generics ownership-semantics rust

8
推荐指数
1
解决办法
332
查看次数

我如何*不*删除析构函数中的成员?

我希望我的类的析构函数删除整个对象,除了其中一个成员,在其他地方删除.首先,这是完全不合理的吗?假设不是,我该怎么做?我认为创建一个带有空体的析构函数会阻止所有成员被删除(因为析构函数不会做任何事情),但似乎并非如此.

c++ destructor ownership-semantics

6
推荐指数
2
解决办法
1323
查看次数

对unique_ptr拥有对象的唯一所有权是什么意思?

我知道std::unique_ptr在对象只有一个所有者std::shared_ptr时使用,而在对象有多个所有者时使用。成为对象的唯一所有者意味着什么?

成为唯一所有者是否意味着没有其他人可以看到该物体?

get()将指针作为引用传递时,可以使用该方法返回原始指针吗?

我觉得,如果必须使用get(),那么我要么通过使用转移了所有权std::move,要么使用了共享指针。

c++ ownership-semantics unique-ptr

6
推荐指数
1
解决办法
107
查看次数