【问题标题】:Wrong move constructor for a struct with arrays带有数组的结构的错误移动构造函数
【发布时间】:2018-08-21 19:44:52
【问题描述】:

尝试调试和理解一个似乎是移动构造函数的小问题,问题仅出现在 Visual Studio 2017 15.6.1,发布版本中。

这里是代码(重现问题最少):


#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>

const size_t kSize = 16;

class Symbol
{
  public:
    explicit Symbol(const char *const name = nullptr)
     : name_{0}
    {
      if (name)
        std::memcpy(name_, name, strlen(name));
    }

    Symbol(const Symbol& other)
    {
       std::memcpy(name_, other.name_, sizeof(name_));
    }

    Symbol& operator=(const Symbol& other)
    {
       if (this != &other)
         std::memcpy(name_, other.name_, sizeof(name_));

       return *this;
    }

    Symbol(Symbol&& other) noexcept
    {
       std::memcpy(name_, other.name_, sizeof(name_));
       std::memset(other.name_, 0, sizeof(other.name_));
    }

    const char* GetSymbolName(void) const { return name_; }

  private:
    char name_[kSize];
 };

struct MyTestMessage
{
   Symbol   symbol;
   int32_t  type;
   int32_t  other;
   int32_t  status;
   int32_t  reserved[5];

   MyTestMessage() = default;
   MyTestMessage(const MyTestMessage& msg) = default;
   MyTestMessage(MyTestMessage&& msg) = default;

   /*
   MyTestMessage(MyTestMessage&& msg) noexcept
     : symbol(std::move(msg.symbol))
  {
    status = msg.status;
    other = msg.other;
    type = msg.type;
  }*/
};

void Print(const std::vector<MyTestMessage>& data)
{
   std::cout << "------------" << std::endl;
   std::for_each(data.cbegin(), data.cend(), [](const MyTestMessage& msg)
 {
    std::cout <<msg.symbol.GetSymbolName() << " " << msg.other << " " << 
              msg.status << " " << msg.type << std::endl;
  });
}

int main()
{
  std::vector<MyTestMessage> my_test;

  MyTestMessage msg;
  msg.other = 5;
  msg.symbol = Symbol("TEST");
  msg.type = 5;
  msg.status = 5;

  my_test.push_back(msg);
  Print(my_test);
  my_test.push_back(msg);
  Print(my_test);

  return 0;

}

或者你可以在这里获取代码coliru link

这是 Visual Studio 发布版本的输出:


测试 5 5 5


测试 5 5 0

测试 5 5 5


问题是那个 0 是从哪里来的?

“修复”的两种方法:

  • 为 MyTestMessage 添加移动构造函数,目前已被注释掉。

  • 或注释 std::memset(other.name_, 0, sizeof(other.name_));在符号移动构造函数中。

删除 MyTestMessage 中的任何数据成员(类型、其他、状态)后,问题就消失了。

但我不相信其中任何一个都是正确的。

有什么想法我在这里做错了吗?

编辑: 编译器版本为visual studio 2017 15.6.1 并且实际上设法找到了改变输出的编译器设置: 如果“启用 IntrinsicFunctions”设置为:是 (/Oi) 问题可重现,如果设置为否,则按预期工作。

更新: 微软回应称,这确实是一个 bug,并且已经在 VS2017 15.7 Preview 1 中修复。

【问题讨论】:

  • Can't reproduce,物有所值。
  • 想法:使用调试器...
  • 我无法复制。请仔细检查您的 MCVE。也许您需要包含一些编译器设置。
  • 罪魁祸首似乎是 Visual Studio 2017 15.6.1 上的“启用内在功能”
  • 您应该自行回答这个问题,以明确这是一个错误。

标签: c++ c++11 visual-c++ move-semantics


【解决方案1】:

所以代码没有问题。

这似乎是 VS 中的一个错误。据称已在 VS2017 15.7 Preview 1 中修复。

【讨论】:

    【解决方案2】:

    有什么想法我在这里做错了吗?

    您在不需要时使用指针。只需使用:

     struct Symbol { char name[kSize]; };
    

    对于您在示例中的内容。 ...尽管坦率地说,除非有充分的理由不这样做,否则请坚持使用std::string

    【讨论】:

    • Symbol("TEST") 不会编译。
    • @IgorTandetnik:是的,它会 - 如果你使用大括号;见here
    • 无论如何,这并不能真正回答问题。原始代码对我来说看起来是正确的,具有明确定义的行为,应该会产生预期的输出。关于风格点的争论并没有说明为什么这段代码(据称)不能像写的那样工作。
    • @IgorTandetnik:OP 没有问为什么代码不能像写的那样工作(实际上它可能只是......),他问他做错了什么。我已经回答过了。
    • @einpoklum 实际代码更复杂,这是重现问题的最少代码量。一方面,字符串可能会使用动态内存,这会降低性能。
    猜你喜欢
    • 1970-01-01
    • 2015-06-30
    • 2014-06-11
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多