2

したがって、次のコードがクラッシュする理由に興味があります。助けていただければ幸いです。

#include <iostream>
using namespace std;

class temp
{    
  public:

    temp(int i)
    {
        intPtr = new int(i);
    }

    ~temp()
    {
        delete intPtr;
    }

  private:
    int* intPtr;
};

void f (temp fInput)
{
    cout << "f called" << endl;
}

int main()
{
    temp x = 2;
    f(x);
    return 0;
}
4

4 に答える 4

5

あなたは3つのルールに違反しています

ポインター メンバーを保持し、オブジェクトのコピーを関数に渡しますf。したがって、最終結果はdelete、同じポインターで 2 回呼び出すことになります。

于 2012-04-04T21:20:50.897 に答える
5

x が渡されるとポインターがコピーされ (暗黙のコピー コンストラクター)、デストラクタが 2 回 (関数が戻る前とメインが戻る前に) 呼び出されるため、メモリは 2 回削除されます。

std::shared_ptr<int>生の int ポインターの代わりにここで使用します (動作を同じにしたい、つまりint両方tempの から同じものを参照したい場合、それ以外の場合は、コピー コンストラクター、ムーブ コンストラクター、および代入演算子を自分で実装します)。

#include <memory>

class temp {    
public:
  temp(int i) : intPtr(std::make_shared<int>(i)) {

  }

private:
  std::shared_ptr<int> intPtr; // reference counting ftw
};
于 2012-04-04T21:20:15.413 に答える
5

クラッシュは、あなたが通り過ぎる方法が原因で発生しますx

f関数のスコープの後、xの destructure が呼び出され、 が削除されintPtrます。

ただし、これにより、まだスコープ内にあるメモリが削除されmainます。そのため、return 0が呼び出された後、同じポインターで delete を 2 回呼び出しているため、既に存在するメモリを削除しようとします。

このエラーを修正するには、変更します

void f (temp fInput)

void f (const temp& fInput)

または、 std::shared_ptrを使用して調べることもできます。

于 2012-04-04T21:20:23.370 に答える
1

ここで発生している問題は、二重削除です。ここではコピー コンストラクターを定義していないため、C++ が喜んで定義しています。実装は、すべてのコンテンツの浅いコピーを実行することによってこれを行います。

f(x);  

この行は、 のコピーを作成してxに渡すことで機能しfます。この時点で、1 つのメンバーtempを所有する 2 つのインスタンスがあります。intPtr両方のインスタンスがそのポインターを削除し、これがクラッシュの原因である可能性があります。

これを回避するには、いくつかの手順を実行できます

  1. 次のような共有を目的としたポインター型を使用しますshared_ptr<T>
  2. インスタンスが参照によって渡されることを強制する、呼び出し不可能なコピー コンストラクターを作成します。

#2の例は

class temp {
  temp(const temp& other);
  temp& operator=(const temp& other);
public:
  // Same
};

f(x)必要なコピー コンストラクターにアクセスできないため、この行は単純にコンパイルされません。fコピーを防ぐために、代わりに再定義を強制します。

void f(const temp& fInput) {
  ...
}
于 2012-04-04T21:21:03.650 に答える