问题描述
我的软件得到的结果不稳定,我想了解为什么以及如何修改我的代码以获得一致的结果。为了说明这一点,我准备了该软件的模拟样本;下面,我有 2 个主要类,Mother
和 Daughter
;这些是我的主要数据结构,我在许多其他数据结构中使用 Mother
。因此,它本质上是一个抽象类,但不能是纯粹的抽象类,因为一些可观察对象也直接依赖于它,所以我不能在其中编写(据我所知)纯虚函数。类定义如下;
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <vector>
using namespace std;
class Mother {
private:
double some_var_;
public:
Mother() {some_var_ = 0.;}
virtual ~Mother() {}
virtual void print() const
{
std::cout << "printing from mother " << some_var_ << std::endl;
}
virtual void setvar(double v) {some_var_ = v;}
virtual const double var() const {return 0.;}
};
class Daughter : public Mother
{
private:
double new_var_;
public:
Daughter() {new_var_ = 0.;}
virtual ~Daughter() {}
void print() const
{
std::cout << "printing from Daughter " << new_var_ << std::endl;
}
void setvar(double v) {new_var_=v;}
const double var() const {return new_var_;}
};
我通过定义如下的 collection
类与这些数据结构进行交互;
class collection
{
private:
std::vector<Daughter> daughters_;
public:
collection () {Reset();}
virtual ~collection() {}
void Reset() {daughters_.clear();}
Daughter* GetNewDaughter()
{
daughters_.push_back(Daughter());
return &daughters_.back();
}
const std::vector<Daughter>& daughters() {return daughters_;}
};
鉴于这些,我定义了一个 filter
函数来修剪这些数据结构;
template <class T,typename FN>
std::vector<const T*> filter(std::vector<T> objects,FN func)
{
std::vector<const T*> filtered;
for (auto &obj: objects)
{
if (func(&obj)) filtered.push_back(&obj);
}
return filtered;
}
代码体如下;
int main(int argc,char** argv)
{
collection* col = new collection();
for (unsigned int i=0; i<5; i++)
{
Daughter* current = col->GetNewDaughter();
current->setvar(double(i)*2.);
}
std::vector<const Daughter*> filt1 = filter(col->daughters(),[] (const Daughter* d) {return d->var() > 2.;});
std::vector<const Daughter*> filt2;
for (unsigned int i=0; i<col->daughters().size(); i++)
{
const Daughter * current = &(col->daughters())[i];
if (current->var() > 2.) filt2.push_back(current);
}
std::cout << "first filtered" << std::endl;
for (const Daughter * c: filt1) c->print();
std::cout << "second filtered" << std::endl;
for (const Daughter * c: filt2) c->print();
return 0;
}
如您所见,我定义了两个过滤器,一个使用 filter
函数,另一个使用手动,我希望看到相同的结果。但是,我运行了 4 次代码,每次都得到不同的结果;
g++ -Wall -std=c++11 -O3 -fPIC main.cpp -o main
$ ./main
first filtered
printing from Daughter 4
printing from Daughter -2.68156e+154
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 0
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 2.31584e+77
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 6
printing from Daughter 8
second filtered
printing from Daughter 4
printing from Daughter 6
printing from Daughter 8
如您所见,由于某种原因,前 3 次运行完全是垃圾,而最后一次运行符合预期,但似乎完全是随机的,所以我相信我在内存分配过程中做错了。如果有人能告诉我我做错了什么以及为什么我做错了,以及我应该如何更改代码以避免这种不稳定,我将不胜感激。
谢谢!
解决方法
尝试改变:
std::vector<const T*> filter(std::vector<T> objects,FN func)
到
std::vector<const T*> filter(const std::vector<T>& objects,FN func)
恕我直言,您在调用 filter 时创建了 vector 的新实例(副本)。
您“过滤”了 vector 的新实例,在过滤器完成后,向量被删除,结果 std::vector
叶夫根尼是对的。只是对问题的一个小描述。事情是 filter
函数返回指向在调用 filter
函数时创建的临时对象的指针向量(第一个参数 - 向量)。函数完成工作后,filt1
存储指向被销毁对象的无效指针。