如何编写无法删除的getter? 我想拥有变量而不是分享它们。 在这里和那里读书我发现无论我什么回来,记忆都可以被释放
然而我定义它,这是真的吗?
引用,const指针,无论如何,调用getter的函数都可以删除它,而我的私有变量不会被取消但是内存坏了,对吗?
我想开发一个getter,我可以返回我的私有变量,并确保被调用者无法删除它...
我担心,在内部使用私有变量时,被调用者已将其销毁,然后在我内部的下一次尝试使用它时崩溃了我的程序
在第一次尝试中我不想使用boost,因为我试图从这个项目中学到最多,如果没有其他方式可以使用boost,或者如果反过来太复杂/多工作
谢谢,
乔
我的另一个问题并没有真正集中,所以我再次这样做了,问这里问题不是问题,对吧? =]
答案 0 :(得分: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;
(当然,这些都不会有任何意义,但他们会编译)但我不会偶然这样做。如果你没有返回指针,很明显我不应该取得数据的所有权。
“保护您的代码免受Murphy,而不是Machiavelli”通常是一个很好的经验法则。如果他们尝试,您无法阻止人们破坏您的代码。你应该担心的是阻止他们意外地做这件事。
修改强>
在回答您对该问题的评论时:
正如我所说,我正在学习......副本认为被调用者必须释放返回变量的内存,这对被调用者来说更麻烦(甚至认为它是me = 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
都是在堆栈上声明的局部变量。当函数返回时,每个都被清理。对于原始类型(例如int
以及指针),实际上不必发生任何事情(它们没有析构函数)。当它们超出范围时,它们就会消失 - 即使它们指向一些重要的东西,比如堆分配的对象,例如我们的整数。
对于非POD对象,当它们超出范围时,它们的析构函数被调用,因此它们也可以很好地清理,完全由它们自己完成。因此,即使我们使用了比int
更复杂的类型,上面的工作也会很好。我们仍然可以复制非POD对象并按值传递它们。
我希望这有助于澄清一些事情。
答案 1 :(得分:3)
嗯,最安全的方法是按值返回对象的副本:
MyObject GetMyObject() const {return _myObject;}
然后调用者可以用他的副本做任何他想做的事情,这不会影响你。
当然,这确实会导致复制对象的开销......这是否重要取决于对象的复杂程度(因此复制对象的成本有多高)。
下一个最好的方法是返回一个const引用:
const MyObject & GetMyObject() const {return _myObject;}
这将为被调用对象提供一个引用,该对象在技术上可以被删除但通常不会被删除(假设在返回引用时没有传递所有权)。
您可以做的最后一件事是使用引用计数来返回对象的引用。在这种情况下,没有人需要删除该对象,因为当对象的最后一次引用消失时,该对象将被自动删除。查看boost的shared_ptr类了解详细信息;我强烈建议将引用计数作为管理C ++中内存分配的一种方法,因为它可以自动消除程序员在管理内存时可能产生的99%的错误。
答案 2 :(得分:3)
在C ++中,您无法阻止调用者崩溃程序。周期。
我建议只返回一个参考。如果呼叫者去了并取了那个地址并将其传递给delete
,那么他们就会遇到麻烦 - 如果他们想要破坏它们,那么你就无法阻止它们。
答案 3 :(得分:1)
你可以使用弱指针。弱指针指的是共享智能指针所拥有的资源,而不会添加其引用计数。 (但是,只要用户可以从智能指针实现裸指针 - 没有它,它将只是智能,而不再是指针 - 它们可以在那上面调用delete
。但是没关系:如果人们想要破坏他们的代码,他们总会想办法做到这一点。看看你的目标是阻止墨菲做他的工作,而不是Macchiavelli。
当然,您也可以返回参考。 (与上述相同的免责声明适用。)
如果您的对象副本便宜,您也可以返回副本。 (而且,从理论上讲,仍然可以将副本的地址传递给delete
。)
答案 4 :(得分:0)
如果按值返回,则来电者将无权访问您的内部成员。
答案 5 :(得分:0)
真正临时的解决方案可能是重载operator new和delete(也许是new [] / delete []),使delete运算符变为私有并仅授予对所有者类的访问权限:
#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
}
然而,只要你没有返回一个错误可能是可以想象的裸指针,如果你要返回一个智能指针,并且调用者仍然决定释放托管指针,那么随后发生的一切将是他们的问题。几乎每当你看到删除调用时,你都知道它一定是个错误。
答案 6 :(得分:0)
您是否考虑过找一些编写删除其他模块变量的代码的人,并将它们喷涂到puce或类似的东西上?
说真的,如果你的同事绝对决定要破坏它们,那么你真的没什么可做的(除非他们当场解雇,如果你是老板)。哎呀,不能保证你传出的东西是单独分配的东西,如果调用者在随机地址上使用delete
,就不知道会发生什么(除了某种形式的堆腐败几乎可以肯定)。
没有编程语言构造或编程语言,这将使你从这样的同事中获益。 “反对愚蠢,众神本身就是徒劳无功。”
答案 7 :(得分: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
句柄无效,因此它们会留下陈旧的指针。这可以通过更多的努力来解决,但是你又要留下它是否真的值得的问题。
答案 8 :(得分:-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
}