这是C++吗?指针容器安全吗?

发布于 2024-09-30 21:49:52 字数 856 浏览 5 评论 0原文

我想要一个类似于 boost 的 scoped_ptr 的安全 C++ 指针容器,但具有类似值的复制语义。我打算将其用于应用程序最内层循环中非常频繁使用的类中很少使用的元素,以获得更好的内存局部性。换句话说,我不关心此类的性能,只要它的“内联”内存负载很小即​​可。

我已经从以下内容开始,但我对此不太擅长;以下安全吗?我是否在重新发明轮子?如果是,我应该去哪里寻找?

template <typename T> 
class copy_ptr {
    T* item;
public:
    explicit copy_ptr() : item(0) {}
    explicit copy_ptr(T const& existingItem) : item(new T(existingItem)) {}
    copy_ptr(copy_ptr<T> const & other) : item(new T(*other.item)) {}
    ~copy_ptr()  { delete item;item=0;}

    T  * get() const {return item;}
    T & operator*() const {return *item;}
    T * operator->() const {return item;}
};

编辑:是的,我们故意让它的行为与正常值非常相似。分析表明该算法在其他方面相当有效,但有时会受到缓存未命中的阻碍。因此,我尝试通过提取当前包含在值中但实际上并未在最内层循环中使用的大 blob 来减小对象的大小。我更愿意在不进行语义更改的情况下做到这一点 - 一个简单的模板包装器将是理想的选择。

I want a safe C++ pointer container similar to boost's scoped_ptr, but with value-like copy semantics. I intend to use this for a very-rarely used element of very-heavily used class in the innermost loop of an application to gain better memory locality. In other words, I don't care about performance of this class so long as its "in-line" memory load is small.

I've started out with the following, but I'm not that adept at this; is the following safe? Am I reinventing the wheel and if so, where should I look?

template <typename T> 
class copy_ptr {
    T* item;
public:
    explicit copy_ptr() : item(0) {}
    explicit copy_ptr(T const& existingItem) : item(new T(existingItem)) {}
    copy_ptr(copy_ptr<T> const & other) : item(new T(*other.item)) {}
    ~copy_ptr()  { delete item;item=0;}

    T  * get() const {return item;}
    T & operator*() const {return *item;}
    T * operator->() const {return item;}
};

Edit: yes, it's intentional that this behaves pretty much exactly like a normal value. Profiling shows that the algorithm is otherwise fairly efficient but is sometimes hampered by cache misses. As such, I'm trying to reduce the size of the object by extracting large blobs that are currently included by value but aren't actually used in the innermost loops. I'd prefer to do that without semantic changes - a simple template wrapper would be ideal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

永言不败 2024-10-07 21:49:52

不,不是。

您忘记了赋值运算符。

您可以选择通过将赋值运算符声明为私有(并且不实现它)来禁止赋值(允许复制时很奇怪),或者您可以这样实现它:

copy_ptr& operator=(copy_ptr const& rhs)
{
  using std::swap;

  copy_ptr tmp(rhs);
  swap(this->item, tmp.item);
  return *this;
}

您还忘记了在复制构造函数中 other.item< /code> 可能为 null(由于默认构造函数),请选择您的替代方案:

// 1. Remove the default constructor

// 2. Implement the default constructor as
copy_ptr(): item(new T()) {}

// 3. Implement the copy constructor as
copy_ptr(copy_ptr const& rhs): item(other.item ? new T(*other.item) : 0) {}

对于类似值的行为,我更喜欢 2,因为值不能为 null。如果您允许空值,请在 operator->operator* 中引入 assert(item); 以确保正确性(在调试模式下) )或抛出异常(无论你喜欢什么)。

最后,析构函数中的 item = 0 是无用的:一旦对象被销毁,你就无法在不调用未定义行为的情况下使用该对象......

还有 Roger Pate 关于 const-ness 传播更“有价值”的评论-like”,但这更多的是语义问题而不是正确性问题。

No it is not.

You have forgotten the Assignment Operator.

You can choose to either forbid assignment (strange when copying is allowed) by declaring the Assignment Operator private (and not implementing it), or you can implement it thus:

copy_ptr& operator=(copy_ptr const& rhs)
{
  using std::swap;

  copy_ptr tmp(rhs);
  swap(this->item, tmp.item);
  return *this;
}

You have also forgotten in the copy constructor that other.item may be null (as a consequence of the default constructor), pick up your alternative:

// 1. Remove the default constructor

// 2. Implement the default constructor as
copy_ptr(): item(new T()) {}

// 3. Implement the copy constructor as
copy_ptr(copy_ptr const& rhs): item(other.item ? new T(*other.item) : 0) {}

For value-like behavior I would prefer 2, since a value cannot be null. If you go for allowing nullity, introduces assert(item); in both operator-> and operator* to ensure correctness (in debug mode) or throw an exception (whatever you prefer).

Finally the item = 0 in the destructor is useless: you cannot use the object once it's been destroyed anyway without invoking undefined behavior...

There's also Roger Pate's remark about const-ness propagation to be more "value-like" but it's more a matter of semantics than correctness.

风吹雪碎 2024-10-07 21:49:52

您应该“传递” copy_ptr 类型的 const-ness:

T* get() { return item; }
T& operator*() { return *item; }
T* operator->() { return item; }

T const* get() const { return item; }
T const& operator*() const { return *item; }
T const* operator->() const { return item; }

在复制构造函数中不需要指定 T:

copy_ptr(copy_ptr const &other) : item (new T(*other)) {}

为什么要显式设置默认构造函数?仅当您计划在某个地方使用 UB 时,将 dtor 中的指针清空才有意义...

但这些都是小问题,您所拥有的几乎就是这样。是的,我已经多次看到这个发明,但人们每次都会稍微调整语义。您可能会查看 boost::Optional,因为这几乎就是您在呈现时所写的内容,除非您要添加移动语义和其他操作。

You should "pass on" the const-ness of the copy_ptr type:

T* get() { return item; }
T& operator*() { return *item; }
T* operator->() { return item; }

T const* get() const { return item; }
T const& operator*() const { return *item; }
T const* operator->() const { return item; }

Specifying T isn't needed in the copy ctor:

copy_ptr(copy_ptr const &other) : item (new T(*other)) {}

Why did you make the default ctor explicit? Nulling the pointer in the dtor only makes sense if you plan on UB somewhere...

But these are all minor issues, what you have there is pretty much it. And yes, I've seen this invented many times over, but people tend to tweak the semantics just slightly each time. You might look at boost::optional, as that's almost what you have written here as you present it, unless you're adding move semantics and other operations.

残龙傲雪 2024-10-07 21:49:52

除了罗杰所说的之外,您还可以通过谷歌搜索“clone_ptr”来获取想法/比较。

In addition to what Roger has said, you can Google 'clone_ptr' for ideas/comparisons.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文