1

削除できないゲッターの書き方は?変数を所有し、共有したくない。あちこち読んで、何を返してもメモリを解放できることがわかりました

しかし、私はそれを定義しますが、これは本当ですか?

参照、constポインター、何があっても、getterを呼び出している関数はそれを削除でき、私のプライベート変数は無効になりませんが、メモリが壊れていますよね?

プライベート変数を返すことができ、呼び出し先がそれを削除できないことを確認できるゲッターを開発したいと思います...

プライベート変数を内部で使用しているときに、呼び出し先がそれを破棄し、次に内部で使用しようとすると、プログラムがクラッシュするのではないかと心配しています。

最初の試みでは、ブーストを使用したくありません。このプロジェクトから最も多くを学ぼうとしているので、ブーストは、他の方法ではない場合、または他の方法が複雑すぎる/非常に手間がかかる場合に使用されます。

ありがとう、

ジョー

私の他の質問はあまり焦点が当てられていなかったので、もう一度やり直しました。ここで質問するのは問題ではありませんよね?=]

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指しますが、オブジェクトを削除する必要があるのは1回だけです。ただし、、、、、およびはすべてローカル変数であり、スタックで宣言されていiます。関数が戻ると、それぞれがクリーンアップされます。プリミティブ型(sやポインターなど)の場合、実際には何も発生する必要はありません(デストラクタはありません)。スコープから外れると、整数などのヒープに割り当てられたオブジェクトなど、重要なものを指していても、消えてしまいます。jkpqint

非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

C ++では、呼び出し元がプログラムをクラッシュさせないようにするためにできることは何もありません。限目。

参照を返すことをお勧めします。発信者がそのアドレスを取得してに渡す場合delete、彼らはトラブルを求めています-そして、彼らが物事を壊すことにそれほど熱心である場合、あなたがそれらを止めるためにできることはあまりありません。

于 2009-10-20T21:34:25.533 に答える
1

そのために弱ポインタ​​を使用できます。ウィークポインターは、参照カウントに追加せずに、共有スマートポインターが所有するリソースを参照します。(ただし、ユーザーがスマートポインターからネイキッドポインターを取得できる限り、それがないと、スマートポインターのみが作成され、ポインターは使用できなくなります。ただし、ユーザーはそれを呼び出すことができdeleteます。ただし、ユーザーがクラッシュしたい場合は、コード、彼らは常にこれを行う方法を見つけるでしょう。マキアヴェッリではなく、マーフィーが彼の仕事をするのを防ぐことであなたの目標を見てください。

もちろん、参照を返すこともできます。(上記と同じ免責事項が適用されます。)

オブジェクトのコピーが安価な場合は、コピーを返却することもできます。(そして、構文的には、コピーのアドレスをに渡すことはまだ可能deleteです。)

于 2009-10-20T21:27:34.117 に答える
0

これがあなたが探しているものであるかどうかはわかりません。また、実際にどれだけの労力を費やす必要があるかにもよりますが、いつでもpimplイディオムを使用できます。

公開したくないメンバーをまとめて、ハンドルを渡します。ハンドルは、値によって楽しく渡すことができる単なる軽量のラッパーです。各ハンドルは、内部コードのみが実際に作成および破棄できる、同じ基になる一意のデータを指すだけです。

例えば、

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

本当にアドホックな解決策は、演算子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
}

ただし、間違いが考えられる場所でネイキッドポインターを返さない限り、スマートポインターを返す場合でも、呼び出し元がマネージポインターを解放することを決定した場合、その後のすべてが問題になります。削除の呼び出しを見ると、ほとんどの場合、それはエラーであるに違いないことがわかります。

于 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 に答える