c++ - 单例模式 : different behavior of auto_ptr and unique_ptr

标签 c++ static linker singleton auto-ptr

在实现工厂类时,我遇到了一个我无法理解的 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/

相关文章:

linux - 无法识别共享库文件格式

导入库可以同时包含 stub 和静态代码吗?

c++ - std::vector insert 的行为与我预期的不同。这是一个错误吗?

c++ - 通过引用传递指针 C++

c++ - 更正 Xcode 中的工作流以避免错误 : duplicate symbols for Architecture x86_64

c - Malloc 与 C 中的静态数组

c - 究竟如何在 C 中使用文件范围的静态变量?

c++ - 使用 C++ 创建直方图(家庭作业)

C++11 线程不适用于虚拟成员函数

c++ - Eigen c++ 中的乘法矩阵给出了错误的维度