简体   繁体   English

std :: make_shared的奇怪行为

[英]Strange behaviour of std::make_shared

I have a very strange behaviour I can't understand. 我有一个非常奇怪的行为,我无法理解。

This test passes: 该测试通过:

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

But this not: 但这不是:

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

I got an error: 我收到一个错误:

Expected: static_cast(*str) 预期:static_cast(* str)

Which is: "p\\x15\\x97\\x1" 这是:“ p \\ x15 \\ x97 \\ x1”

To be equal to: "Bye!" 等于:“再见!”

The CipString's code: 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 */
};

This line: 这行:

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

creates a shared_ptr that is destroyed just after the ; 创建一个shared_ptr,它在;之后被销毁; . str is a dangling pointer after that, and your test invokes undefined behavior by accessing freed memory. 之后, str是一个悬空指针,您的测试通过访问释放的内存来调用未定义的行为。

You are basically asserting against garbage memory. 您基本上是在声明垃圾内存。

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

decomposes to: 分解为:

1) call make_shared to return a shared_ptr 1)调用make_shared返回shared_ptr

2) get the address of the underlying object 2)获取底层对象的地址

3) construct the CipString with the pointer to the underlying object 3)使用指向基础对象的指针构造CipString

4) destroy the shared_ptr 4)销毁shared_ptr

which is 'fine' 很好

This this decomposes to: 这分解为:

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

1) construct a shared_ptr 1)构造一个shared_ptr

2) get the address of the underlying object 2)获取底层对象的地址

3) create a temporary CipString from it and store the address in str 3)从中创建一个临时CipString并将地址存储在str中

4) destroy the shared_ptr 4)销毁shared_ptr

5) destroy the temporary CipString (which str is pointing at) 5)销毁临时CipString(str指向的)

which means that this: 这意味着:

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

becomes undefined behaviour 变成不确定的行为

You can rewrite this: 您可以重写以下内容:

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

as: 如:

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

And this has no Undefined Behaviour. 这没有未定义的行为。 On the other hand this code: 另一方面,此代码:

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

would be rewritten as: 将被重写为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM