返回指向函数静态数据的指针是否合适?

时间:2012-07-14 19:17:52

标签: c++ templates pointers c++11

好吧,我需要返回一个指向将在函数内创建的类实例的指针。这个合适吗?

这是示例代码:

template <typename T>
ImplicatedMembershipFunction<T>* 
TriangularMF<T>::minImplicate(const T &constantSet) const
{
    static ImplicatedType* resultingSet = new ImplicatedType();
    // do something to generate resultingSet...
    return resultingSet;
}

我想返回指针,因为需要在容器中有基类的子类。在上面的代码中,ImplicatedTypeTriangularMF<T>中定义的类,派生自ImplicatedMembershipFunction<T>。将有各种模板类,如TriangularMF,它们具有从ImplicatedMembershipFunction<T>派生的嵌套类,我需要以相同的方式处理它们。例如,在图书馆外,我可能想要做类似的事情:

TriangularMF<double> trmf(0,1,2);
TrapesoidalMF<double> trpmf(0,1,3,2); // a class like TriangularMF but
                                      // ImplicatedType is different 
ImplicatedMembershipFunction<double>* itrmf = trmf.implicate(0.6);
ImplicatedMembershipFunction<double>* itrpmf = trpmf.implicate(0.6); // same as above.

// use them in the same way:
vector<ImplicatedMembershipFunction<double>*> vec;
vec.push_back(itrmf); 
vec.push_back(itrpmf);

我不想使用移动语义或std::shared_ptr等C ++ 11功能的原因是我不想强迫我的队友在他们的计算机上安装更新版本的g ++。我不能给他们一个库的编译版本,因为它很有模板。

修改 该库将是线程化的。特别是,TriangularMF<T>::minImplicate将同时在多个线程中运行。因此,使minImplicate变成一个mutal任务,对性能毫无意义。

3 个答案:

答案 0 :(得分:3)

这是单身人士常用的习语:

class CMyClass {};

CMyClass& MyClass() {
  static CMyClass mclass;
  return mclass;
}

CMyClass将在第一个MyClass()函数调用上构建。

它看起来很像你的代码,指针除外,它会导致破坏这种crated实例的问题。如果你不想在这里使用shared_ptr,那么考虑编写你自己的shared_ptr之类的模板,那么它应该可以正常工作。

[编辑]如果这个代码将在多线程环境中使用,那么在这里使用智能指针将是棘手的

答案 1 :(得分:3)

返回指针本身不是问题,但你必须定义一个关于whoi创建和销毁谁的干净“策略”。

在您的代码中,您定义了一个静态指针,该指针在遇到其(指针)定义时首次使用new对象进行初始化。

指针本身将在main()返回后被销毁,但它指向的对象呢? 如果你让别的东西来处理删除,你的函数将继续返回指针,即使对象不再存在。如果你把它放在那里,它将在程序结束时被杀死(不是“危险的”泄漏,因为它只是一个对象,但如果它的析构函数必须采取一些明智的行动呢?)

您最有可能声明,而不是静态指针,而是静态OBJECT,并返回...其地址或其引用。

以这种方式,对象被授予存在直到程序终止并在main()返回后被正确销毁。

template <typename T>
ImplicatedMembershipFunction<T>* 
TriangularMF<T>::minImplicate(const T &constantSet) const
{
    static ImplicatedType resultingSet(....);
    return &resultingSet;
} 

请注意,我删除了你的“做某事......”,因为它每次都会被执行(不仅仅是第一次)。要初始化ImplicatedType,你最好依赖构造函数。 或者,如果您无法一次性构建它,请执行类似

的操作
template <typename T>
ImplicatedMembershipFunction<T>* 
TriangularMF<T>::minImplicate(const T &constantSet) const
{
    static ImplicatedType* resultingSet=0;
    static bool init=true;
    if(init)
    {
        init=false; 
        static ImplicatedType result;
        resultingSet=&result;
        // do something to generate resultingSet...
    }
    return resultingSet;
}

如果您处于多线程情况,还需要一个静态互斥锁,然后在if(init)之前将其锁定,并在返回时解锁。

答案 2 :(得分:1)

您可以使用此技术,但返回引用。如果调用者需要指向存储的指针,则可以获取结果的地址。

template <typename T>
ImplicatedMembershipFunction<T> &
TriangularMF<T>::minImplicate(const T &constantSet) const
{
    static ImplicatedType* resultingSet = new ImplicatedType();
    // do something to generate resultingSet...
    return *resultingSet;
}

但是,代码的危险在于它本身并不是MT安全的。但是,如果您知道minImplicate中的代码是线程安全的,或者您的代码是单线程的,则没有问题。