std :: make_shared的奇怪行为

时间:2016-04-22 14:25:03

标签: c++ c++11 shared-ptr

我有一种我无法理解的非常奇怪的行为。

此测试通过:

CipString str = *std::make_shared<CipString>("Bye!").get();
EXPECT_EQ(static_cast<std::string>(str), "Bye!"); 

但这不是:

CipString *str = std::make_shared<CipString>("Bye!").get();
EXPECT_EQ(static_cast<std::string>(*str), "Bye!");

我收到了一个错误:

  

预期:static_cast(* str)

     

这是:&#34; p \ x15 \ x97 \ x1&#34;

     

等于:&#34;再见!&#34;

CipString的代码:

class CipString{
  public:

  CipString(const std::string& str) {
    length = str.size();
    string.reset(new uint8_t[length]);
    std::copy(str.begin(), str.end(), string.get());
  }

  operator std::string() const {
    std::string str("", length);
    std::copy(string.get(), string.get() + length, str.begin());
    return str;
  }

  uint16_t length; /**< Length of the String (16 bit value) */
  std::shared_ptr<uint8_t> string; /**< Pointer to the string data */
};

3 个答案:

答案 0 :(得分:8)

这一行:

CipString *str = std::make_shared<CipString>("Bye!").get();

创建一个在;之后销毁的shared_ptr。 str之后是一个悬空指针,您的测试通过访问释放的内存来调用未定义的行为。

你基本上是在反对垃圾内存。

答案 1 :(得分:0)

CipString str = *std::make_shared<CipString>("Bye!").get();
EXPECT_EQ(static_cast<std::string>(str), "Bye!"); 

分解为:

1)调用make_shared返回shared_ptr

2)获取基础对象的地址

3)使用指向底层对象的指针

构造CipString

4)销毁shared_ptr

这是很好的&#39;

这分解为:

CipString *str = std::make_shared<CipString>("Bye!").get();

1)构建一个shared_ptr

2)获取基础对象的地址

3)从中创建一个临时CipString并将地址存储在str

4)销毁shared_ptr

5)销毁临时CipString(str指向的)

这意味着:

EXPECT_EQ(static_cast<std::string>(*str), "Bye!");

成为未定义的行为

答案 2 :(得分:0)

你可以改写:

CipString str = *std::make_shared<CipString>("Bye!").get();
EXPECT_EQ(static_cast<std::string>(str), "Bye!"); 

为:

CipString str;
{
   auto sp = std::make_shared<CipString>("Bye!");
   str = *sp.get(); // here a copy is made (in original code copy initialization)
   // here sp will get destroyed
}
// here str contains correct "Bye!" value

这没有未定义的行为。另一方面,这段代码:

CipString *str = std::make_shared<CipString>("Bye!").get();

将被重写为:

CipString *str;
{
   auto sp = std::make_shared<CipString>("Bye!");
   str = sp.get(); // here a pointer is assigned to str, no copy is done as above
   // here sp will get destroyed, and also pointer to 
   //  which str points will be a dangling pointer
}
// here str should not be used - as it is UB