【问题标题】:Which is a better practice for a reset function?哪个是重置功能的更好做法?
【发布时间】:2015-04-22 08:29:56
【问题描述】:

编辑MyClass 只是一个例子。问题实际上是关于如何重置类的部分成员。在我的真实案例中,这个类更复杂,data 会长达一百万。另外,我有复制/移动 c'tors 和操作符,在我的示例中省略了。

我有课

class MyClass{
     double *data;
     int data_length;         

     MyClass() : data(nullptr), data_length(0){}

     ~MyClass(){
         if(data != nullptr){
             delete[] data;
         }
     }
}

现在我想添加一个新的成员函数reset()。 以下哪一项是更好的做法?

(a)

MyClass::reset(double* in_data, int in_length){
    if(data != nullptr){
        delete[] data;
    }
    data = new double[in_length];
    memcpy(data, in_data, in_length * sizeof(double));
    data_length = in_length;
}

(b)

MyClass::reset(double* in_data, int in_length){
    if(data != nullptr){
        delete[] data;
    }
    data = in_data;
    data_length = in_length;
}

看起来(a)比较安全,但是比较耗时,而且(a)的客户端调用reset()后必须手动删除tempin_data。 (b) 效率更高,但有客户端可能会在外面删除in_data的风险。

【问题讨论】:

  • 为什么要“重置”一个对象? (另外,为什么没有std::<shared/unique>_ptr ?)
  • 在第一个变体中,您错过了分配。无论如何,您已经发现了引入移动语义的问题。什么更好取决于您的用例。
  • std::vector 看起来更合适,但是是的,为什么要推出自己的内存管理?这些东西存在于标准库中;你只需要使用它,而不是重新实现它。 (旁注:delete nullptr; 什么都不做,所以不需要检查)
  • @JBL 只是一个例子。如果一个类有多个数据指针,我想更改其中一个。我想重置它,而不是重建整个班级。
  • 如果你的类 MyClass 是一个资源类,用所有的常规成员尽可能简单地编写它。然后,您将使用 MyClass 的实例而不是无风险的双指针。如果这不是练习,请使用 std::vector。

标签: c++ memory reset


【解决方案1】:

只要有一个数据成员:

std::vector<double> data;

然后:

void reset(std::vector<double>&& new_data) { data = std::move(new_data); }
void reset(const std::vector<double>& new_data) { data = new_data; }

如果隐式允许或您在调用代码中使用std::move() 显式授予权限,则上述第一个重载将从过期的vector&lt;&gt; 中移动数据,否则第二个重载将复制:

myClass.reset(get_new_data_vector());  // moves returned vector

std::vector x = { ... };
myClass.reset(x); // do a full "deep" copy
myClass.reset(std::move(x));  // explicitly allow move from named local var

如果您有其他数据集合,您可以为每个数据集执行类似的操作 - 每个数据集都可以有效且独立地更新。

【讨论】:

  • 如果数据足够长,可能值得将reset 拆分为两个重载,分别采用左值和右值引用。
  • 优化器不能总是改变你的代码,你要求的是特定的操作,那些操作会被执行。问题是如果内部缓冲区已经足够大以容纳新值并且调用者正在使用左值(即他们仍然想要调用 reset 之后的值)。数据可以原地复制,但使用按值参数强制分配,复制元素并销毁旧元素并释放旧缓冲区[类型为double 意味着销毁是不- op,但请耐心等待],其中单个 memcpy 可以工作
  • @DavidRodríguez-dribeas:我被卖掉了——感谢您引导我完成它。干杯。
【解决方案2】:

最好是复制数据而不是依赖外部世界来获取这些东西,尤其是当你有一个析构函数会删除类没有分配的内存时。

【讨论】:

  • “删除他们没有分配的内存”......这就是析构函数的好处,不是吗?通常内存是在构造函数(或其他地方)中分配的,很少在析构函数中分配。
  • @tobi303 我不明白你的意思。而且我还没有提到任何关于在析构函数中分配内存的内容。哦,我明白了,在“它没有分配的内存”中,“它”代表班级。所以我想指出的是,在 b) OP 的情况下,MyClass 会释放它没有分配的内存,这对我来说是一种代码味道。
猜你喜欢
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多