36

宣言によってC++でポインターを削除しないようにする方法はありますか?

運が悪いので、次のコードを試しました。

const int* const foo()
{
    static int a;
    return &a;
}

int main()
{
    const int* const a = foo();

    *a = 1;   //compiler error, const int*
    a++;      //compiler error, int* const
    delete a; //no compiler error, I want to have compiler error here

    return 0;
}
4

5 に答える 5

39

ポインターでの呼び出しを防止する方法で、任意の型へのポインターを宣言することはできませんdeleteconst (T const*) へのポインターを削除すると、その理由が説明されます。

それがカスタム クラスへのポインターである場合delete、オペレーターを非公開にすることができます。

class C {
    void operator delete( void * ) {}
};

int main() {
    C *c;
    delete c; // Compile error here - C::operator delete is private!
}

スタック上にオブジェクトを作成することも回避されるため、(他の人が示唆しているように) デストラクタをプライベートにするべきではありません。

class C {
    ~C() {}
};

int main() {
    C c; // Compile error here - C::~C is private!
}
于 2012-08-08T14:11:06.107 に答える
17

簡単な答えはノーです。組み込み型へのポインターで delete が呼び出されるのを防ぐ方法はありません。

補遺:

ただし、これと同様の状況に遭遇しました..私の解決策は、通常のポインターの使用を停止することでした。したがって、削除について心配する必要はありません。私の場合、共有ポインターは理にかなっていますが、独自のポインターまたは類似のもので十分かもしれません。

//Custom do nothing deleter.
template<typename T> dont_delete( T* ) { /* Do Nothing */ }

shared_ptr<const int> const foo()
{
  static int a;
  return shared_ptr<const int>(&a, &dont_delete<const int> );
}

shared_ptr<const int> const bar()
{
  return shared_ptr<const int>(new int(7) );
}

main()
{
   shared_ptr<const int> p1 = foo();
   shared_ptr<const int> p2 = bar();

   //p1s data _not_ deleted here, 
   //p2s data is deleted here
}
于 2012-08-08T14:10:44.830 に答える
1

私はあなたが何を求めているのか完全には理解していません。削除できないオブジェクトが必要な場合は、foo をクラスにして、デストラクタをプライベートにすることができます。

class Foo {
public:
   int a;

   Foo(int v) {
       a = b;
   }

private:
   ~Foo() { }
};

int main() {

    Foo *c = new Foo(1);

    delete c; // compiler error, ~Foo() is private

    return 0;
}

変数 "a" はもともと構造体として定義されていたのでパブリックにしましたが、それをプライベートにして、元のコード例で必要なアクセス ルールを強制するアクセサーを作成することができます (またそうすべきです)。

これは絶対確実ではなく、コンパイラはそのクラスへの直接参照のみをキャッチします。

于 2012-08-08T14:18:16.423 に答える
0

特定のクラスのポインターでの削除演算子の使用を防ぐことができます。例えば:

class Object {
public: void operator delete(void* p) = delete;
};

class Entity : public Object {    };

int main(int argc, char const *argv[])
{
    Object* o = new Object;
    Entity* e = new Entity;

    delete o; // compiler error
    delete e; // compiler error

    return 0;
}

Object::operator の削除が削除されたため、Object から継承するすべてのクラスを削除できません。Object クラスを派生またはインスタンス化するときにコンパイラ エラーが発生するため、この演算子をプライベートとしてマークしないでください。まだそうすることができることに注意してください。

::operator delete(o);

o ポインターは解放されますが、デストラクタは呼び出されません。クラスを使用して、オブジェクト クラスの寿命を管理します。簡単な実装は次のようになります。

class Object {
    template<typename type> friend class ptr;
    public: void operator delete(void* p) = delete;
};

class Entity : public Object { };

template<typename type>
class Ptr {
public:
    Ptr(type* obj) : o(obj){}
    ~Ptr() { o->~type(); ::operator delete(o); }
private: type* o;
};

int main(int argc, char const *argv[])
{
    Object* o = new Object;
    Entity* e = new Entity;

    // delete o;  // error
    // delete e;  // error

    Ptr<Entity> ent = new Entity; // Ptr will delete ent for you.

    return 0;
}
于 2016-05-27T15:18:14.423 に答える
0

彼が意味しているのは、プログラムのクラッシュにつながる可能性のある偶発的なオブジェクトの削除 (delete o または free(o) のいずれか) が発生しないようにすることだと思います。オブジェクトがヒープに割り当てられている場合、これを回避する方法は実際にはありません。スタックポインタに関する限り、それが起こり得ないことは誰もが知っています。最上位クラスで保護された dtor を使用することはオプションですが、子クラスの dtor でそれを呼び出す必要があります。

1 つの解決策 (削除演算子がテーブル上にある場合でも) は、id/token/what-have-you を返すテーブル マッピング システムを使用することですが、これは実際には CSTYLE コードで記述し、C 規則でコンパイルする場合にのみ機能します。 . これを行う利点は、オブジェクト ポインターがユーザーから隠されているため、ユーザーはオブジェクトにマップされたトークンを渡すことができます。これには、作業と経験が必要です。

ほとんどの経験豊富で賢明なプログラマーは、この事故を避けるために API のドキュメントを読んでいるので、私はそれについて心配することさえありません。賢くないか経験がないなら、まあ、私は何を言うべきではありません.

于 2014-10-23T10:35:45.563 に答える