如何正确组织共享类成员?

时间:2009-07-06 20:14:50

标签: c++

假设我有一个n个变量x [0] .. x [n-1]:

的函数y
y = 1 + a[0][0]*x[0] + a[1][0]*x[0]^2 + a[0][1]*x[1] + a[1][1]*x[1]^2 + ...

我想找到变量x [0] .. x [n-1]的值,它们最小化y。该优化任务将由遗传算法执行。该算法的基本步骤是:

  1. 生成随机解x [0] .. x [n-1](也称染色体)的池(群)
  2. 评估这些随机解y = F(x [0],..,x [n-1])
  3. 将池解决方案分为两组:y值较低(最佳解决方案)和y值较高(解决方案较差)。
  4. 抛弃糟糕的解决方案并通过交叉来交换最好的解决方案(交换不同解决方案的单个元素x [j])。
  5. 通过向选定元素x [j]添加随机值来突变新解决方案。我们得到了一个新的解决方案池。
  6. 重复2-5,直到达到停止标准。
  7. 以下是实现上述算法的两个类的代码:

    • 类Solution,它描述了与该解决方案相关的单个解x [0] .. x [n-1],y值,以及函数y = F(x [0],。 。,X [N-1])。

    • 类Pool,描述了不同解决方案的集合以及选择,繁殖和变异的功能。

    以下是代码:

    class Solution
    {
        double *x;
        double y;
        double **a; // the same for all instances
        int n; // the same for all instances
    public:
        Solution(int,double*);
        ~Solution();
        double yFunc();
    }
    
    class Pool
    {
        vector<Solution> sols;
        int poolSize;
        // other private members
    public:
        Pool(int,int,double*);
        ~Pool();
        // other public functions
    }
    
    // construct Solution
    Solution::Solution(int numX,double **coef)
    {
        n=numX;
        // allocate memory for coefficients
        a = new double*[2];
        for(int i=0;i<2;i++) a[i] = new double[n];
        // assign coefficients
        for(int i=0;i<2;i++) 
            for(int j=0;j<n;j++)
                a[i][j] = coef[i][j];
        // generate a random solution in [-1,+1] range
        srand(time(0));
        for(int j=0;j<n;j++)
            x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
    }
    
    // destroy Solution
    Solution::~Solution()
    {
        delete[] x;
        for(int i=0;i<2;i++) delete[] a[i];
        delete[] a;
    }
    
    // define optimized function
    double Solution::yFunc()
    {
        double sum=1.0;
        for(int j=0;j<n;j++)
            sum += a[0][j]*x[j]+a[1][j]*x[j]*x[j];
        return sum;
    }
    
    // construct Pool
    Pool::Pool(int numSols, int numX, double **coef)
    {
        poolSize = numSols;
        for(int i=0;i<poolSize;i++)
        {
            Solution sol = new Solution (numX,coef);
            sols.push_back(sol);
        }
    }
    

    我只有一个问题:

    当我构造解决方案池时,我创建了许多类Solution的实例,它们各自的向量x [0] .. x [n-1]和相应的函数值y。然而,函数y = F(x [0],..,x [n-1])的a [] []系数和函数本身也得到实例化的poolSize次,即使它们对于所有解向量都是相同的

    如何修改代码,只创建[] [],F(x [0],..,x [n-1])和n的单个实例?我听说过静态成员,但据我所知,用户不允许通过外部函数调用来分配它们的值。这些静态成员只能在类或静态Solution()函数中初始化,除了任何参数之外。

    即使有办法使用外部用户提供的值初始化这些静态成员,它们也不是多线程安全的。所以,我正在寻找一种方法将类Solution的共享成员与各个成员分开,以避免实例化共享成员poolSize次。

5 个答案:

答案 0 :(得分:1)

您对静力学的理解似乎有些偏差。静态变量只是该类的所有实例共享的变量。您可以像访问任何非静态变量一样访问它,但您也可以在没有类实例的情况下访问它。

对于一个SO答案,这个主题可能有点宽泛,并且最好通过一本优秀的C ++教科书来解决 - 您使用的是哪一本?也许如果您尝试修改代码以使用静态,然后发布有关您遇到的问题的问题,我们可以提供更多帮助。

答案 1 :(得分:0)

听起来你已经选择了一些C#或Java传闻并将其与C ++混淆。

C ++中没有“静态构造函数”功能。另一方面,在任何这些语言中分配静态成员变量都没有问题。最后,在任何情况下,它都不是解决问题的好方法!

首先,在您想要致电std::vector的任何地方,始终使用new[]std::vector的重点是不需要手动分配的数组。

要实际解决您的问题,您需要将共享数据放在一个单独的对象中,然后所有其他对象都持有指针。在C ++中执行此操作以便在不再需要时删除共享对象的最简单方法是在当前编译器/库中使用boost shared_ptr,也称为std::tr1::shared_ptr

或者为了娱乐,你可以自己实现同样的事情。只需在共享类中放置一个整数计数器。每次新客户端获取指向该类的共享对象的指针时,它们都会递增计数器。在他们的析构函数中(或当他们清除指针时)然后首先减少计数器。当计数器降至零时,删除共享对象。

class SharedThing
{
    int needed;

    // other data

public:
    SharedThing()
        : needed(1) { }

    SharedThing *share()
    {
        needed++;
        return this;
    }

    void release()
    {
        if (--needed == 0)
            delete this;
    }
};


SharedThing *a = new SharedThing();
SharedThing *b = a->share();
SharedThing *c = b->share();

// a, b, and c all point to the same object, 
// which now internally has a 'needed' count of 3

a->release(); // down to 2
b->release(); // down to 1
c->release(); // deleted

从每个本地代码段的角度看,指向SharedThing的指针,在调用release之后,你应该假设它已被删除。

shared_ptr模板类使此工具可重复使用,因此您无需手动调用或实施sharerelease

再次更新

根据您添加的信息,共享数据看起来与类Pool的对象具有相同的生命周期。因此,让Pool为其所有者,负责分配(并设置)并删除它。

我再说一遍,使用std::vector<T>,而不是原始的new T[]数组。

答案 2 :(得分:0)

  

我听说过静态会员,但就像我一样   明白,不允许用户   通过分配他们的价值观   外部函数调用。

错误。

class A
{
  public:
    static int x_;

    static void StaticSetX(int x) { x_ = x; }
    void NeedInstanceSetX(int x) { x_ = x; }
};

int main()
{
    // an instance of A can access both static methods and non static
    A a;
    a.NeedInstanceSetX(1);
    a.StaticSetX(2);

    A::NeedInstanceSetX(4); // Compiler error, method not static
    A::StaticSetX(3); // Ok, StaticSetX() is a static method

    return 0;
}

答案 3 :(得分:0)

对静态成员没有多少经验,以下是我修改代码的方法。 (解决方案的静态成员** a和n在池构造函数内初始化)

class Solution
{
    double *x;
    double y;
    static double **a; // the same for all instances
    static int n; // the same for all instances
public:
    static void StaticSet(int,double**)
    Solution();
    ~Solution();
    double yFunc();
}
// assign static variables
Solution::StaticSet(int numX,double **coef)
{
    n=numX;
    // allocate memory for coefficients
    a = new double*[2];
    for(int i=0;i<2;i++) a[i] = new double[n];
    // assign coefficients
    for(int i=0;i<2;i++) 
        for(int j=0;j<n;j++)
            a[i][j] = coef[i][j];
}

// construct Solution
Solution::Solution()
{
    // generate a random solution in [-1,+1] range
    srand(time(0));
    for(int j=0;j<n;j++)
        x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
}

// construct Pool
Pool::Pool(int numSols, int numX, double **coef)
{
    poolSize = numSols;
    Solution::StaticSet(numX,coef);
    for(int i=0;i<poolSize;i++)
        sols.push_back(new Solution());
}

这是对的吗?

答案 4 :(得分:0)

看看你想要做什么,将a / n值视为其他东西可能更简单......怎么样:

class Target
{
public:
    double **a; // the same for all instances
    int n; // the same for all instances
    Target(int,double **);
    ~Target();
};

class Solution
{
    double *x;
    double y;
    Target *t
public:
    Solution(Target *t);
    ~Solution();
    double yFunc();
}

class Pool
{
    vector<Solution> sols;
    int poolSize;
    // other private members
public:
    Pool(int,int,double*);
    ~Pool();
    // other public functions
}

// construct Solution
Target::Target(int numX,double **coef)
{
    n=numX;
    // allocate memory for coefficients
    a = new double*[2];
    for(int i=0;i<2;i++) a[i] = new double[n];
    // assign coefficients
    for(int i=0;i<2;i++) 
        for(int j=0;j<n;j++)
                a[i][j] = coef[i][j];
}

Solution::Solution(Target *in_t)
{
    t=in_t;
    // generate a random solution in [-1,+1] range
    srand(time(0));
    for(int j=0;j<t->n;j++)
        x[j] = 2.0*(rand()/(double)RAND_MAX-0.5);
}

// destroy Solution
Target::~Target()
{
    for(int i=0;i<2;i++) delete[] a[i];
    delete[] a;
}

Solution::~Solution()
{
    delete[] x;
}

// define optimized function
double Solution::yFunc()
{
    double sum=1.0;
    for(int j=0;j<t->n;j++)
        sum += t->a[0][j]*x[j]+t->a[1][j]*x[j]*x[j];
    return sum;
}

// construct Pool
Pool::Pool(int numSols, int numX, double **coef)
{
    poolSize = numSols;
    Target target(numX,coef);

    for(int i=0;i<poolSize;i++)
    {
        Solution sol = new Solution (&target);
        sols.push_back(sol);
    }
}

现在您有一个Target对象和一个解决方案,它是参照Target创建的。