声明现有原始指针所有权的正确方法

Correct way to claim ownership of existing raw pointer

我有一些代码声明了一系列原始指针的所有权,我想知道是否有可接受的方法来做到这一点?我正在寻找的是一种在更大程度上强制执行代码所有权的方法。主要是,我一直在想我的构造函数是否应该直接采用唯一指针的向量。

作为旁注,一旦所有权被声明,数据就应该是不可变的。

代码大致遵循下面 class X 的模式。

#include <iostream>
#include <memory>
#include <vector>
using namespace std; // For readability purposes only

class X {
public:
    const vector< unique_ptr<const int> > data; // In my case this is private

    // Constructor: X object will take ownership of the data 
    // destroying it when going out of scope
    X (vector<int*> rawData) 
        : data { make_move_iterator(rawData.begin()), make_move_iterator(rawData.end()) }
    { }
};


int main() {
    // Illustrating some issues with claiming ownership of existing pointers:
    vector<int*> rawData { new int(9) , new int(4) };
    int* rawPointer = rawData[0];
    { // New scope
        X x(rawData);
        cout << *(x.data[0]) << endl; // Unique pointer points to 9
        *rawPointer = 7;
        cout << *(x.data[0]) << endl; // Unique pointer points to 7
    }
    cout << *rawPointer << endl; // The pointer has been deleted, prints garbage
    return 0;
}

你犯了几个错误。

  1. 如果是const vector< unique_ptr<const int> >数据;移动迭代器确实没有多大意义。原因是,int* 没有移动构造函数。

  2. 如果你用 vector < int* > 调用 X 的构造函数 X (vector<int*> rawData) 那么 vector < int* > 的复制构造函数就会被调用,但这不是你想要的想要。 顺便提一句。使用 move 的原因是为了避免大内存复制。例如 std::vector < int* >std::vector<int*> 的成员属性大小和指向存储 int* 的内存位置的指针也必须通过移动复制,而不是 int*s自己。一个结论是,移动是为了主张所有权。

  3. 如果您想要这样的共享指针,请使用 std::shared_ptr。它拥有一个计数器,它计算指向它自己的指针。

´ 我的示例代码:

class X
{
public:
    const std::vector< std::shared_ptr< const int> > data; // In my case this is private

    // Constructor: X object will take ownership of the data 
    // destroying it when going out of scope
    X (std::vector<std::shared_ptr<int>>& rawData) 
        //: data(rawData)
        : data(rawData.cbegin(), rawData.cend())
    { }
};


int main() {
    // Illustrating some issues with claiming ownership of existing pointers:
    std::vector<std::shared_ptr<int>> rawData { std::make_shared<int>(9), std::make_shared<int>(4) };
    int* rawPointer = rawData[0].get();
    { // New scope
        X x(rawData);
        cout << *(x.data[0]) << endl; // Unique pointer points to 9
        *rawPointer = 7;
        cout << *(x.data[0]) << endl; // Unique pointer points to 7
    }
    cout << *rawPointer << endl; // The pointer has been deleted, prints not more garbage
    return 0;
}

如果您不想使用 std::shared_ptr,您将需要一个 GC。

如果不详细了解您的情况,很难post回答。但我的建议是一旦知道就将您的数据附加到 unique_ptr。然后,您可以随意将 unique_ptr 移入和移出 vector。例如:

#include <iostream>
#include <memory>
#include <vector>
using namespace std; // For readability purposes only

class X {
public:
    const vector< unique_ptr<const int> > data; // In my case this is private

    // Constructor: X object will take ownership of the data 
    // destroying it when going out of scope
    X (vector<unique_ptr<const int>>&& v) 
        : data { std::move(v) }
    { }
};

vector<unique_ptr<const int>>
collectRawData()
{
    auto rawData = {9, 4};
    vector<unique_ptr<const int>> data;
    for (auto const& x : rawData)
        data.push_back(make_unique<int>(x));
    return data;
}

int main() {
    auto rawData = collectRawData();
    { // New scope
        X x(std::move(rawData));
        cout << *(x.data[0]) << endl; // Unique pointer points to 9
        cout << *(x.data[1]) << endl; // Unique pointer points to 4
    }
}