Visual c++ 加密++;SHA1函数

Visual c++ 加密++;SHA1函数,visual-c++,crypto++,Visual C++,Crypto++,我无法找出我的函数有什么问题-它在返回时会导致断点 std::string generateHash(std::string source) { CryptoPP::SHA1 hash; byte digest[CryptoPP::SHA1::DIGESTSIZE]; hash.CalculateDigest(digest, (const byte*)source.c_str(), source.size()); std::string output; C

我无法找出我的函数有什么问题-它在返回时会导致断点

std::string generateHash(std::string source)
{
    CryptoPP::SHA1 hash;
    byte digest[CryptoPP::SHA1::DIGESTSIZE];
    hash.CalculateDigest(digest, (const byte*)source.c_str(), source.size());
    std::string output;
    CryptoPP::HexEncoder encoder;
    CryptoPP::StringSink test = CryptoPP::StringSink(output);
    encoder.Attach((CryptoPP::BufferedTransformation*)&CryptoPP::StringSink(output));
    encoder.Put(digest, sizeof(digest));
    encoder.MessageEnd();
    return output; // here
}
encoder.Attach((CryptoPP::BufferedTransformation*)和CryptoPP::StringSink(输出))

在这一行中,
CryptoPP::StringSink(输出)
是一个临时对象。在此调用之后,
CryptoPP::StringSink(输出)
不再存在。因此,如果您尝试跟随它的地址(
encoder.Attach
encoder.Put
),您将得到未定义的行为。(就像您永远不应该返回局部变量的地址一样)

我的参考代码:

 std::string generateHash(std::string source)
  {
      CryptoPP::SHA1 hash;
      byte digest[CryptoPP::SHA1::DIGESTSIZE];
      hash.CalculateDigest(digest, (const byte*)source.c_str(), source.size());
      std::string output;
      CryptoPP::HexEncoder encoder;
      CryptoPP::StringSink test = CryptoPP::StringSink(output);
      encoder.Attach(new CryptoPP::StringSink(output));
      encoder.Put(digest, sizeof(digest));
      encoder.MessageEnd();
      return output;
  }
Onemouth的解决方案是正确的,但以下是您遇到问题的原因:

  • StringSink(输出)
    是堆栈上的临时文件,当
    StringSink
    析构函数运行时,它将被清除
  • HexEncoder
    拥有指向
    StringSink(输出)
    的指针,因此
    HexEncoder
    将在
    StringSink(输出)
因此,
StringSink
被清理两次

为完整起见,
StringSink
不会删除字符串
output
,因为它采用的是引用,而不是指针

这是以下文件中记录的行为:

虽然这是非常不寻常的,但您可能能够按照以下方式执行您正在尝试执行的操作并修复它(但我不建议您以这种方式执行):

重定向器
停止所有权链。当
重定向程序
被销毁时,它不会销毁其附加的转换(即
StringSink
)。但是,这不是使用图书馆的方式

Redirector
s在库中的其他位置很有用,但在这种情况下并非如此

   CryptoPP::HexEncoder encoder;
   CryptoPP::StringSink test = CryptoPP::StringSink(output);
   encoder.Attach((CryptoPP::BufferedTransformation*)&CryptoPP::StringSink(output));
88  *** Important Usage Notes ***
89  
90  1. If a constructor for A takes a pointer to an object B (except primitive
91  types such as int and char), then A owns B and will delete B at A's
92  destruction.  If a constructor for A takes a reference to an object B,
93  then the caller retains ownership of B and should not destroy it until
94  A no longer needs it. 
encoder.Attach(new Redirector(&CryptoPP::StringSink(output)));