Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用CxxTest损坏的单例数据_C++_Static_Singleton_Coredump - Fatal编程技术网

C++ 使用CxxTest损坏的单例数据

C++ 使用CxxTest损坏的单例数据,c++,static,singleton,coredump,C++,Static,Singleton,Coredump,这是一个奇怪的问题,我不知道该怎么办 我有如下几点: struct Parms { const std::string value1; const std::string value2; std::string parm1; std::string parm2; Parms() : parm1(value1), parm2(value1) {} static const Parms& getDefaults() {

这是一个奇怪的问题,我不知道该怎么办

我有如下几点:

struct Parms
{
    const std::string value1;
    const std::string value2;

    std::string parm1;
    std::string parm2;

    Parms() : parm1(value1), parm2(value1) {}

    static const Parms& getDefaults()
    {
        static Parms defaults;
        return defaults;
    }
};
我通常这样使用:

Parms myParms = Parms::getDefaults();
myParms.parm1 = "crap";
functionThatNeedsParms(myParms);
很简单。这从来没有给我带来任何麻烦,直到我开始尝试使用CxxTest编写使用这段代码的单元测试。我在不同的文件中有两个测试套件类,当我单独运行它们时,一切都很好

当我把它们放在一起时,我看到了两件坏事。首先,整个内核转储都试图双重释放静态默认值变量。其次,如果我在默认值消失之前的某个时间查看它的内容,但在我开始使用它之后,其中的静态const std::string已损坏(有些字母已随机更改,但每次运行时都是相同的)


<> P> > C和C++中的静态变量不是线程安全的。这意味着,如果两个线程试图访问您的singleton对象,可能会发生争用条件(坏事情)。解决问题的一种方法是使用线程本地存储。pthreads库支持这一点,一些编译器也直接支持线程本地存储

如果您的单线程必须对所有线程都是全局的,那么另一种选择是提供锁,以确保一次只有一个线程可以访问您的数据


然而,问题只出现在单元测试中。我建议不要运行多线程单元测试,除非您打算在多个线程中使用单线程。

< P> C和C++中的静态变量不是线程安全的。这意味着,如果两个线程试图访问您的singleton对象,可能会发生争用条件(坏事情)。解决问题的一种方法是使用线程本地存储。pthreads库支持这一点,一些编译器也直接支持线程本地存储

如果您的单线程必须对所有线程都是全局的,那么另一种选择是提供锁,以确保一次只有一个线程可以访问您的数据


然而,问题只出现在单元测试中。我建议不要运行多线程单元测试,除非您打算在多线程中使用单线程。

这在很大程度上取决于您正在使用的编译器和平台,在没有实际看到测试的情况下,我只能猜测发生了什么。

我在您的代码中看到一些误解:
1) 缺少复制运算符和复制构造函数 您正在复制包含
std::string
的实例,该实例可能使用引用计数实现。引用计数是在
std::string
的重载复制构造函数/运算符中实现的,但是这些可能不会从类的隐式生成的复制构造函数中调用,因此会导致双重释放内存和其他讨厌的事情。复制运算符/构造函数应如下所示:

// Copy constructor
Parms(const Parms& oth)  { parm1 = oth.parm1; parm2 = oth.parm2; }

// Copy operator
Parms& operator= (const Parms& oth)  { 
  if (&oth == this)  // Check for self-assignment
    return *this;
  parm1 = oth.parm1;
  parm2 = oth.parm2;
  return *this;
}


2) 我不太理解
value1
value2
的存在。似乎您从未初始化它们,您只是在默认构造函数中使用它们将其(空)内容复制到
parm1
parm2
中。您可以完全避免这种情况,因为调用时,
parm1
parm2
会自动初始化为空字符串。

3) 这里不需要使用单例模式。
getDefaults()
方法可以实现如下:

static Parms getParms() { return Parms(); }
singleton模式适用于在整个程序运行过程中只有一个实例的类,而您的类似乎不是这样


通过这种方式,您可以从多个线程安全地使用
getParms()
函数,智能编译器将优化出隐含的附加副本。

这在很大程度上取决于您使用的编译器和平台,在没有实际看到测试的情况下,我只能猜测正在进行的操作。

我在您的代码中看到一些误解:
1) 缺少复制运算符和复制构造函数 您正在复制包含
std::string
的实例,该实例可能使用引用计数实现。引用计数是在
std::string
的重载复制构造函数/运算符中实现的,但是这些可能不会从类的隐式生成的复制构造函数中调用,因此会导致双重释放内存和其他讨厌的事情。复制运算符/构造函数应如下所示:

// Copy constructor
Parms(const Parms& oth)  { parm1 = oth.parm1; parm2 = oth.parm2; }

// Copy operator
Parms& operator= (const Parms& oth)  { 
  if (&oth == this)  // Check for self-assignment
    return *this;
  parm1 = oth.parm1;
  parm2 = oth.parm2;
  return *this;
}


2) 我不太理解
value1
value2
的存在。似乎您从未初始化它们,您只是在默认构造函数中使用它们将其(空)内容复制到
parm1
parm2
中。您可以完全避免这种情况,因为调用时,
parm1
parm2
会自动初始化为空字符串。

3) 这里不需要使用单例模式。
getDefaults()
方法可以实现如下:

static Parms getParms() { return Parms(); }
singleton模式适用于在整个程序运行过程中只有一个实例的类,而您的类似乎不是这样

通过这种方式,您可以从多个线程安全地使用
getParms()
函数,并且智能编译器将优化隐含的额外副本。

双重空闲和核心转储 我想我可以解释你所面临的“双重免费和核心转储”问题。我最近遇到了同样的事情,听起来你在做和我一样的事情

根据您的描述,您说过,当您“单独运行它们”时,它们工作正常,但如果您“一起运行”,则会出现双自由/核心转储问题

我发现如果两次声明同一个全局变量,就会发生这种情况

在我的例子中,我有一个foo类,在一个文件中,我有一个全局
类foo-gFoo类foo-gFoo。(是的,这听起来很愚蠢,实际上我是在链接一个文件X.cxx a