在实现工厂类时,我遇到了一个我无法理解的 std::auto_ptr
行为。我将问题简化为以下小程序,所以...让我们开始吧。
考虑以下单例类:
单例.h
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include<iostream>
#include<memory>
class singleton {
public:
static singleton* get() {
std::cout << "singleton::get()" << std::endl;
if ( !ptr_.get() ) {
std::cout << &ptr_ << std::endl;
ptr_.reset( new singleton );
std::cout << "CREATED" << std::endl;
}
return ptr_.get();
}
~singleton(){
std::cout << "DELETED" << std::endl;
}
private:
singleton() {}
singleton(const singleton&){}
static std::auto_ptr< singleton > ptr_;
//static std::unique_ptr< singleton > ptr_;
};
#endif
单例.cpp
#include<singleton.h>o
std::auto_ptr< singleton > singleton::ptr_(0);
//std::unique_ptr< singleton > singleton::ptr_;
这里使用智能指针来管理资源主要是为了避免程序退出时的泄漏。然后我在以下程序中使用此代码:
啊啊
#ifndef A_H_
#define A_H_
int foo();
#endif
a.cpp
#include<singleton.h>
namespace {
singleton * dummy( singleton::get() );
}
int foo() {
singleton * pt = singleton::get();
return 0;
}
主要.cpp
#include<a.h>
int main() {
int a = foo();
return 0;
}
现在是有趣的部分。我分别编译了三个源:
$ g++ -I./ singleton.cpp -c
$ g++ -I./ a.cpp -c
$ g++ -I./ main.cpp -c
如果我按此顺序明确链接它们:
$ g++ main.o singleton.o a.o
一切都如我所料,我将以下内容输出到标准输出:
singleton::get()
0x804a0d4
CREATED
singleton::get()
DELETED
如果我改为使用此顺序链接源:
$ g++ a.o main.o singleton.o
我得到这个输出:
singleton::get()
0x804a0dc
CREATED
singleton::get()
0x804a0dc
CREATED
DELETED
我尝试了不同的编译器品牌(Intel 和 GNU)和版本,这种行为在它们之间是一致的。无论如何,我看不到其行为取决于链接顺序的代码。
此外,如果 auto_ptr
被替换为 unique_ptr
,则行为始终与我期望的正确行为一致。
这让我想到了一个问题:有人知道这里发生了什么吗?
最佳答案
dummy
的顺序和 std::auto_ptr< singleton > singleton::ptr_(0)
构造是未指定的。
对于 auto_ptr
案例,如果你构建dummy
然后 singleton::ptr_(0)
,在 dummy
中创造的值(value)ptr_(0)
的构造函数删除调用.
我会在 ptr_
的构造中添加跟踪通过ptr_(([](){ std::cout << "made ptr_\n"; }(),0));
或类似的东西。
它与 unique_ptr
一起工作的事实是巧合,可能是由于优化 unique_ptr(0)
可以弄清楚它已归零,因为这样什么都不做(static
数据在构造开始之前被归零,所以如果编译器可以弄清楚 unique_ptr(0)
只是将内存归零,它可以合法地跳过构造函数,这意味着你不再将内存归零)。
解决这个问题的一种方法是使用一种保证在使用前构造的方法,例如:
static std::auto_ptr< singleton >& get_ptr() {
static std::auto_ptr< singleton > ptr_(0);
return ptr_;
}
并替换对 ptr_
的引用与 get_ptr()
.
关于c++ - 单例模式 : different behavior of auto_ptr and unique_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16177840/