【问题标题】:Testing whether an object has been moved from测试对象是否已从
【发布时间】:2012-11-10 23:42:06
【问题描述】:

我正在测试我的容器包装器是否正确实现了 URef。我能想到的唯一明显的方法是尝试找出一种方法来检测对象是否已移动。

有没有一种很好的测试方法来确保对象没有被复制?还是有另一种方法来测试我想要什么?我更喜欢不需要修改我正在测试的类的解决方案。因为有几十个。

您能否提供更多有关您拥有的信息的信息?比如你的容器是什么,你如何使用它,你能不能修改它等等。也许你可以在不修改你的容器的情况下测试它,而是使用特殊的容器元素类型——它跟踪副本和移动。

几个不同的容器和一些独立的模板函数。大多数情况下,它是 STL 库类型(如 deque、list、map、set 等)的包装器。

【问题讨论】:

  • “搬家”并不是像骑自行车那样的实际活动。相反,所发生的只是一个函数对您的对象有一个可变引用。引用本身并没有任何事情。它只是编写高效代码的语法基础。
  • 我知道 std::move 实际上除了返回对内部内容的 r 值引用之外并没有做任何事情。我想问我想要什么的更具体的方式是,"I have an object that I think might have had its innards ripped out; how do I confirm that's actually what happened?"
  • 我认为可能的唯一方法是直接查看相关操作之前和之后的对象二进制表示,然后memcmping 这些。
  • 基本正确。 reinterpret_cast,然后将 memcpy 放入缓冲区,然后将 memcmp 与操作后转换的对象一起使用。如果你的胆子被掏空,某事应该已经改变了。当然,一个类可以使用 pimpl 惯用语并直接从实现中移动,而不是将指针移动到实现,但在这种情况下无论如何你都搞砸了。如果发生这种情况,并且您所讨论的课程提供了明确的移动前后条件以及评估这些条件的方法,那可能是另一种方式(想想.empty() 用于容器)。
  • 为了将来参考,内存检查并非在所有情况下都有效。使用接受的答案。

标签: c++ c++11 move-semantics universal-reference


【解决方案1】:

有没有一种很好的测试方法来确保对象没有被复制?

您可以尝试以下检查:

live demo

#include <boost/container/vector.hpp>
#include <iostream>
#include <ostream>
#include <vector>
#include <string>

using namespace boost;
using namespace std;

struct Test
{
    bool copied;
    Test()
        : copied(false)
    {
    }
    Test(const Test&)
        : copied(true)
    {
    }
};

template<typename Container>
void check_move_constructor()
{
    Container from(1);
    Container to(boost::move(from));
    cout << "\tmove constructor is" << (to[0].copied ? " not" : "") << " working" << endl;
}

template<typename Container>
void check_move_assignment()
{
    Container from(1);
    Container to;
    to=boost::move(from);
    cout << "\tmove assignment is" << (to[0].copied ? " not" : "") << " working" << endl;
}

template<typename Container>
void check_move(const string &name)
{
    cout << name << " :" << endl;
    check_move_constructor< Container >();
    check_move_assignment< Container >();
    cout << string(16,'_') << endl;
}

int main()
{
    cout << boolalpha;
    check_move< container::vector<Test> >("boost::container::vector");
    check_move< vector<Test> >("std::vector");
    return 0;
}

MSVC2008 输出:

boost::container::vector :
        move constructor is working
        move assignment is working
________________
std::vector :
        move constructor is not working
        move assignment is not working
________________

注意,在这段代码中,我使用了从左值显式移动,所以复制省略在这里不起作用。







附:另一种方法是检查生成的汇编代码。例如 MSVC 上的 /FA 编译器选项或 GCC 上的 -S。

你可以用特殊的函数调用来标记感兴趣的地方:

__declspec(noinline) void asm_marker(int line) { volatile int i=line; };
#define ASM_MARKER asm_marker(__LINE__)

并将该标记放在代码中:

    ASM_MARKER;
    func_of_interest();
    ASM_MARKER;

Asm 代码可能如下所示:

    mov     ecx, 235                                ; 000000ebH
    call    ?asm_marker@@YAXH@Z                     ; asm_marker
    mov     edi, r12d
    lea     rcx, QWORD PTR [rdi+rdi*4]
    mov     rax, QWORD PTR vec$[rsp]
    lea     r9, QWORD PTR [rax+rcx*8]
    mov     rbx, QWORD PTR vec$[rsp+32]
    mov     ecx, 237                                ; 000000edH
    call    ?asm_marker@@YAXH@Z                     ; asm_marker   

【讨论】:

  • 好的,我会修改我的问题,你对我如何测试这个问题有一个好的答案吗?
  • 虽然有用且信息量很大,但我希望将其添加到我的测试套件中,而不是让它成为我必须定期手动执行的操作。谢谢你的信息。绝对有用。
  • 您能否提供更多有关您拥有的信息的信息?比如你的容器是什么,你如何使用它,你能不能修改它等等。也许你可以在不修改你的容器的情况下测试它,而是使用特殊的容器元素类型——它跟踪副本和移动。
  • “好的,我会修改我的问题,你对我如何测试这个问题有一个好的答案吗?” - 现在我更好地理解了你的问题。事实上,您可以通过使用无法应用复制省略/RVO/NRVO 的上下文来检查您的移动操作。因此,您可以将问题更改为“如何检查移动构造函数和移动分配工作?”
  • 我实际上想检查这两种情况,但我认为你和 Xao 之间有足够的工具来实现这一点。非常感谢您的努力,它非常有帮助。
【解决方案2】:

添加一个在构造对象时设置为false 的布尔字段。在移动构造函数和移动赋值运算符中,将true 分配给要从中移动的对象中的该字段。

【讨论】:

  • 退后一步,似乎就我正在尝试做的工作范围而言,这不切实际。有没有一种方法可以不修改我正在测试的类?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 2011-02-24
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
相关资源
最近更新 更多