1

如何写一个不能删除的getter?我想拥有变量而不是共享它们。在这里和那里阅读我发现无论我返回什么,都可以释放内存

但是我定义它,这是真的吗?

引用,const 指针,无论如何,调用 getter 的函数都可以删除它,我的私有变量不会被无效但内存被破坏,对吧?

我想开发一个吸气剂,我可以在其中返回我的私有变量并确保被调用者不能删除它......

我担心,在内部使用私有变量时,被调用者已经破坏了它,然后它在我内部下次尝试使用它时崩溃了我的程序

在第一次尝试中,我不喜欢使用 boost,因为我想从这个项目中学到最多的东西,如果不是其他方式或者其他方式太复杂/工作量太大,就会使用 boost

谢谢,

我的另一个问题没有真正集中,所以我又做了一次,在这里问问题不是问题,对吧?=]

4

9 回答 9

5

取决于你的意思。任何时候你有一个指针,都可以调用delete它。

如果你有引用,你可以获取它的地址,它会给你一个指针

无论如何,如果你有这个类,例如:

class X {
  int getByVal() { return i; } // returns a copy of i
  int& getByRef() { return i; } // returns a reference to i
private:
  int i;
};

那么我,作为您班级的用户,没有明显的方法来删除您的数据。我可以执行以下操作:

X x;
int j = x.getByVal();
int& k = x.getByRef();
j = 42; // doesn't affect x.i because we returned a copy
k = 42; // sets x.i to 42, because k is a reference

而且我没有明显的方法来删除班级成员。当然,我可以这样做:

delete &j;
delete &k;

(当然,这些都不会做任何有意义的事情,但它们会编译)但我不会偶然这样做。如果你不返回一个指针,很明显我不应该拥有数据的所有权。

“保护你的代码免受墨菲,而不是马基雅维利”通常是一个很好的经验法则。如果有人尝试,您无法阻止他们破坏您的代码。您应该担心的是防止他们意外地这样做。

编辑
针对您在问题下的评论:

正如我所说,我正在学习......副本认为被调用者必须释放返回变量的内存,这对被调用者来说更麻烦(甚至认为是我=p),所以我不是在谈论概念,但是写起来很容易……再说一次,我是这个记忆东西的新手。我在用 C#、PHP 等进行开发。我很久以前在用 CircleMUD 学习的时候用 C 开发

不,副本不必手动删除。局部变量超出范围时会自动删除。所以在上面的例子中,j是类成员的副本i。当调用函数返回时,j会被自动删除。

希望有帮助。C++ 中的变量生命周期规则并不是很复杂,但是正确使用它们非常重要,因为很多代码都依赖于它们。

void foo()
{
  int i = 0; // allocate a local (on the stack) int, and initialize it to 0
  int* p = new int(1); // allocate an int on the heap, and initialize it to 1
  int j = i; // create a *copy* of i. Now we have two ints on the stack
  int k = *p; // create a copy of the int pointed to by p. k is also on the stack, so even though it was copied from a heap-allocated variable, k does not have to be manually deleted
  int* q = p; // create a copy of p. q is not a separate pointer, which points to the *same* heap-allocated integer.
}

foo在上面的例子中,所有的副本在返回时都会被自动清理。我们唯一需要手动做的就是删除我们在堆上分配的整数。两者都p指向q它,但我们只能删除对象一次。但是i, j, k, p, 和q都是局部变量,声明在栈上。当函数返回时,它们中的每一个都会被清除。对于原始类型(例如ints 和指针),实际上不需要发生任何事情(它们没有析构函数)。当它们超出范围时,它们就会消失——即使它们指向一些重要的东西,比如堆分配的对象,比如我们的整数。

对于非 POD 对象,当它们超出范围时,会调用它们的析构函数,因此它们也可以自行清理干净。因此,即使我们使用了比 更复杂的类型int,上面的方法也可以正常工作。我们仍然可以复制非 POD 对象并按值传递它们。

我希望这有助于澄清一些事情。

于 2009-10-20T21:26:45.820 回答
3

好吧,最安全的方法是按值返回对象的副本:

MyObject GetMyObject() const {return _myObject;}

然后调用者可以对他的副本做任何他想做的事情,而且不会影响你。

当然,这确实会产生复制对象的开销……这是否重要取决于对象的复杂程度(以及复制它的成本)。

下一个最好的方法是返回对它的 const 引用:

const MyObject & GetMyObject() const {return _myObject;}

这将为被调用的对象提供一个引用,从技术上讲,它可以被删除,但通常不会被删除(假设在返回引用时没有传递所有权)。

您可以做的最后一件事是使用引用计数来返回对对象的引用。在这种情况下,没有人需要删除该对象,因为当最后一个对它的引用消失时,该对象将被自动删除。查看 boost 的 shared_ptr 类了解详情;我强烈推荐将引用计数作为在 C++ 中管理内存分配的一种方式,因为它可以自动消除程序员在管理内存时所犯的 99% 的潜在错误。

于 2009-10-20T21:27:52.870 回答
3

In C++, there is nothing you can do to prevent the caller from crashing your program. Period.

I would suggest just returning a reference. If the caller goes and takes the address of that and passes it to delete, they're asking for trouble - and if they're that intent on breaking things, there's not much you can do to stop them.

于 2009-10-20T21:34:25.533 回答
1

您可以为此使用弱指针。弱指针指的是共享智能指针所拥有的资源,而不增加其引用计数。(但是,只要用户可以从智能指针获得裸指针——没有它,它只会是smart,而不再是指针——他们可以调用delete它。但这没关系:如果人们想崩溃他们的代码,他们总会想办法做到这一点。看看你的目标是阻止墨菲做他的工作,而不是马基雅维利。

当然,您也可以返回参考。(适用与上述相同的免责声明。)

如果您的对象复制起来很便宜,您也可以返回一个副本。(而且,从语法上讲,仍然可以将副本的地址传递给delete.)

于 2009-10-20T21:27:34.117 回答
0

我不确定这是否是您正在寻找的东西,它还取决于您真正需要付出多少努力,但您始终可以使用pimpl idiom

把你不想暴露的成员包起来,然后把句柄传给它。句柄只是轻量级的包装器,可以通过值愉快地传递,每个句柄只是指向相同的底层唯一数据,只有您的内部代码才能实际创建和销毁。

例如,

class Interface
{
public:
    Data getData() const { return Data( m_data ); }

private:
    DataImpl* m_data;
};

在哪里

class Data
{
public:
    // Just use compiler-synthesised copy ctor, assignment and dtor

    // Declare as many forwarding methods to impl as required
    // ...

private:
    friend class Interface;
    Data( DataImpl* d ) : m_impl( d ) {}
    DataImpl*const m_impl;
};

这里的简单示例是幼稚的,因为当最终销毁时它不会使任何现有Data句柄无效DataImpl,因此它们会留下陈旧的指针。这可以通过更多的努力来解决,但你仍然面临着它是否真的值得的问题。

于 2009-10-20T22:08:53.530 回答
0

如果您按值返回,则调用者将无权访问您的内部成员。

于 2009-10-20T21:24:36.923 回答
0

A really ad hoc solution might be to overload operator new and delete (and perhaps new[]/delete[]), making the delete operator private and granting access only to the owner class:

#include <memory>

class Y
{
private:
    void* operator new(size_t size) { return new char[size]; }
    void operator delete(void* p) { delete [] static_cast<char*>(p); }
    friend class X;
};

class X
{
    Y* p;
    X(const X& x);
    const X& operator=(const X& x);
public:
    X(): p(new Y()) {}
    ~X() { 
        delete p;  //OK here, X is a friend
    }
    const Y* get() const { return p; }
};

int main()
{
    X x;
    const Y* p = x.get();
    delete p;  //error here: operator delete is private
}

However, as long as you don't return a naked pointer where a mistake might be imaginable, if you were to return a smart pointer, and the caller still decided to free the managed pointer, everything that ensues will be their problem. Pretty much any time you see a call to delete, you'd know it must be an error.

于 2009-10-20T21:36:36.533 回答
0

你有没有想过找人写代码来删除其他模块的变量,然后给他们喷漆或类似的东西?

说真的,如果你的同事绝对决心破坏事情,你真的无能为力(除了当场解雇他们,如果你是老板的话)。哎呀,不能保证你传递的东西是单独分配的,如果调用者delete在随机地址上使用,则不知道会发生什么(除了某种形式的堆损坏几乎是肯定的)。

没有任何编程语言结构或编程语言可以让你远离这样的同事。“众神自己对抗愚蠢是徒劳的。”

于 2009-10-20T21:50:53.860 回答
-1

如果您有一个拥有所有权的对象(一家银行需要一个帐户(我知道这是人为的))。
但是人们想要访问该帐户,但您不希望他们删除它。

class Bank
{
    public:
        // use auto_ptr to indicate transfer of ownership to the Bank.
        void addAccount(std::auto_ptr<Account> a)
        {
            m_account = a;
        }
        //
        // getAccount() returns a reference to the object
        // Anbody using the object can NOT now delete it.
        // But they can manipulate it.
        Account&  getAccount(int accountNo)
        {
            return *m_account;
        }
    private:
        std::shared_ptr<Account>   m_account;  // In example bank only has 1 account
}
于 2009-10-20T22:01:34.947 回答