【问题标题】:Can you access methods from a ROOT object when you pass the object as an argument to a function in C++?当您将对象作为参数传递给 C++ 中的函数时,您可以从 ROOT 对象访问方法吗?
【发布时间】:2015-09-24 00:36:54
【问题描述】:

请原谅我的无知,但我是 C++ 和 ROOT 的新手,我不知道自己做错了什么。

我要做的是编写一个函数,该函数返回直方图中 n 峰值的 bin 位置。以下是我的代码:

#include <iostream>
#include <algorithm>
#include <iterator>

#include "TROOT.h"
#include "TCanvas.h"
#include "TH1.h"
#include "TF1.h"

using namespace std;

int *peak_counter1d(TH1F *histogram,int peak_num,int threshold = 5,int display = 0){
  if(display == 1){
    TCanvas *look = new TCanvas("look","look",500,400);
    histogram->Draw();
  }
  int total_bins = histogram->GetNBinsX();
  double peak_bins[peak_num];
  peak_bins[0] = histogram->GetMaximumBin();
  int counter = 1;
  int *check_array; // to put previously found peak bins
  while(counter < peak_num){
    double peak = threshold;
    double peak_loc = -500;
    check_array = new int[counter];
    for(int i=0; i<counter; i++){
      check_array[i] = peak_bins[i]; // fills the array with previously found peak bins
    }
    for(int i=0; i<total_bins; i++){
      if(peak < histogram->GetBinContent(i)){ 
        bool exists = find(begin(check_array),end(checkarray),i); // makes sure this is a peak we haven't already found
        if(!exists){
          peak = histogram->GetBinContent(i);
          peak_loc = i;
        }
      }
    }
    peak_bins[counter] = peak_loc;
    counter ++;
  }
  delete[] check_array;

  return peak_bins;
}

void testing(){
  gROOT->Reset();
  TH1F *histo = new TH1F("histo","try",100,0,10);
  TF1 *f1 = new TF1("f1","exp(-x/10)*sin(x)*sin(x)",0,10);
  double val;
  for(int i=0; i<100; i++){
    val = f1->Eval(i/10.0);
    //cout << i << "\t" << i/100.0 << "\t" << val << endl;
    histo->SetBinContent(i,val);
  }

  int *peak_bins;
  peak_bins = peak_counter1d(histo,3,5,1);
  for(int i=0; i<3; i++){
    cout << i << "\t" << *(peak_bins+i) << endl;
  }
}

当我在 ROOT 中执行此代码时,我得到以下信息:

root [] .x testing.cpp
Error: Can't call TH1F::GetNBinsX() in current scope testing.cpp:15:
Possible candidates are...
(in TH1F)
(in TH1)
*** Interpreter error recovered ***

我认为这是在函数内部访问对象方法的问题,因为当我在 testing() 函数中调用 histo->GetNBinsX() 方法时,我没有遇到任何问题。不过我不知道。

谢谢,如果我正在做其他可怕的编码练习,请告诉我。

【问题讨论】:

  • double peak_bins[peak_num]; 您正在返回一个指向该本地数组的指针。返回指向局部变量的指针是未定义的行为。你也有潜在的内存泄漏:double peak_bins[peak_num]; 这些问题使用std::vector,而不是原始指针。
  • 旁注。我不知道存在 C++ 解释器。而且,返回指向局部变量的指针很糟糕,mmkay?

标签: c++ root-framework


【解决方案1】:

您的代码存在各种问题。

最刺眼的是这个:

int *peak_counter1d(TH1F *histogram,int peak_num,int threshold = 5,int display = 0)
{
    //...
    double peak_bins[peak_num];
    //...
    return peak_bins;
}

您正在返回一个指向局部变量的指针。返回指向局部变量的指针是未定义的行为

下期是这样的:

  int *check_array; // to put previously found peak bins
  while(counter < peak_num)
  {
      //...
      check_array = new int[counter];
  }
  delete[] check_array;

你有一个潜在的内存泄漏,因为你在循环中没有释放check_array。另一个问题是,如果该循环永远不会执行,您将在未初始化的变量上调用 delete []

下期是这样的:

int * peak_counter1d(...)
{
    double peak_bins[peak_num];
    //...
    return peak_bins;
}

即使您可以安全地返回一个指向局部变量的指针,您的函数也会返回一个 int*,但您返回的是一个 double *

下期是这样的:

TCanvas *look = new TCanvas("look","look",500,400);

您正在分配look,但您从未解除分配,甚至从未使用它。

你也在main做同样的事情:

 TH1F *histo = new TH1F("histo","try",100,0,10);
  TF1 *f1 = new TF1("f1","exp(-x/10)*sin(x)*sin(x)",0,10);

C++ 不是 Java。您不必使用new 创建对象。

TH1F histo("histo","try",100,0,10);
  TF1 f1("f1","exp(-x/10)*sin(x)*sin(x)",0,10);

除了最后一个问题,如果您使用std::vector,而不是使用new[] 创建动态数组,总体上这些问题都可以解决。

应用这些更改后,代码应如下所示(未编译):

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>

#include "TROOT.h"
#include "TCanvas.h"
#include "TH1.h"
#include "TF1.h"

using namespace std;

vector<int> peak_counter1d(TH1F *histogram,int peak_num,int threshold = 5,int display = 0)
{
  if(display == 1)
  {
    // TCanvas *look = new TCanvas("look","look",500,400);
     histogram->Draw();
  }
  int total_bins = histogram->GetNBinsX();
  vector<int> peak_bins(peak_num);
  peak_bins[0] = histogram->GetMaximumBin();
  int counter = 1;
  vector<int> check_array; // to put previously found peak bins
  while(counter < peak_num){
    double peak = threshold;
    double peak_loc = -500;
    check_array.resize(counter);
    for(int i=0; i<counter; i++){
      check_array[i] = peak_bins[i]; // fills the array with previously found peak bins
    }
    for(int i=0; i<total_bins; i++){
      if(peak < histogram->GetBinContent(i)){ 
        bool exists = find(begin(check_array),end(checkarray),i); // makes sure this is a peak we haven't already found
        if(!exists){
          peak = histogram->GetBinContent(i);
          peak_loc = i;
        }
      }
    }
    peak_bins[counter] = peak_loc;
    counter ++;
  }
  return peak_bins;
}

void testing(){
  gROOT->Reset();
  TH1F histo("histo","try",100,0,10);
  TF1 f1("f1","exp(-x/10)*sin(x)*sin(x)",0,10);
  double val;
  for(int i=0; i<100; i++){
    val = f1.Eval(i/10.0);
    //cout << i << "\t" << i/100.0 << "\t" << val << endl;
    histo.SetBinContent(i,val);
  }

  vector<int> peak_bins = peak_counter1d(&histo,3,5,1);
  for(int i=0; i<3; i++){
    cout << i << "\t" << peak_bins[i] << endl;
  }
}

【讨论】:

  • 谢谢。我没有意识到我正在返回一个指向局部变量的指针。我也没有意识到向量库是如此有用。但是,我对此确实有两个问题。主要是,您将 TH1F *histo = new TH1F(...) 更改为 TH1F histo(...)。但是,在上面的函数中,您将第一个参数保留为指针。如果从 peak_counter1d(TH1F *histogram,...) 更改为 peak_counter1d(TH1F histogram,...) ,我将不得不更改对吗?另外,原来获取GetNBinsX()的问题还在。
  • 注意,在main中,我传递了变量的地址,所以指针作为第一个参数仍然有效。
【解决方案2】:

已经指出不能返回局部变量的地址,该地址会在函数结束时被销毁。

你的另一个问题是:

histo->GetNbinsX()

不工作。我试图在脚本的主程序和子程序中调用它:它对我来说非常适合,使用当前的 ROOT 版本。在问题中,您拼写错误为GetNBinsX(是的,这与骆驼案政策更加一致)。也许……?

无论如何,我相信您会很高兴知道 ROOT 有一个非常智能的一维峰值搜索算法可供使用:查找 the TSpectrum class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 2020-05-11
    • 1970-01-01
    • 2018-08-04
    • 2018-01-21
    • 2012-02-27
    相关资源
    最近更新 更多