Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid `-Wclass-memaccess` on memcpy of a POD type w/copy disabled

If you turn up your warning level to -Wall, GCC 8 (at least g++ (Ubuntu 8.3.0-6ubuntu1~18.10.1) 8.3.0 with --std=c++17) gives -Wclass-memaccess on:

#ifdef __cplusplus
   #include <type_traits>
#endif
#include <string.h>

struct CantCopy {
    int i;

  #ifdef __cplusplus
    CantCopy () = default;
    CantCopy (const CantCopy &other) = delete;
    void operator= (const CantCopy &rhs) = delete;
  #endif
};

int main(int argc, char *argv[]) {

  #ifdef __cplusplus
    static_assert(std::is_pod<CantCopy>::value);
  #endif

    struct CantCopy src;
    src.i = 1020;

    struct CantCopy dest;
    memcpy(&dest, &src, sizeof(struct CantCopy));

    return 0;
}

The warning says:

warning: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘struct CantCopy’ with no trivial copy-assignment [-Wclass-memaccess]

memcpy(&dest, &src, sizeof(CantCopy));

What I have is code that's intended to build as either C or C++. But the C++ build is supposed to be able to statically check when C programmers are going through direct assignments of the structure--when they should be using a function. Hence disabling copying.

But it's still POD, and all this does was delete the operators. I can see the scenario this warning is designed to help with, but this isn't that situation.

Is there any easy way to do something equivalent to this without needing to disable the warning?

like image 896
HostileFork says dont trust SE Avatar asked Aug 30 '19 05:08

HostileFork says dont trust SE


1 Answers

It seems that you could achieve your aim to make assignments and copies in C++ outside of a designated function impossible better by making the assignment operator and copy constructor default and private and adding your Move_Value(&cantcopy_dest, &cantcopy_src) as a friend.

struct CantCopy;
#ifdef __cplusplus
extern "C" {
#endif
void Move_Value(CantCopy *cantcopy_dest, const CantCopy *cantcopy_src);
#ifdef __cplusplus
} // extern "C"
#endif


struct CantCopy {
    int i;

#ifdef __cplusplus
    CantCopy () = default;
  private:
    CantCopy (const CantCopy &other) = default;
    constexpr CantCopy &operator= (const CantCopy &rhs) = default;

    friend void Move_Value(CantCopy *cantcopy_dest, const CantCopy *cantcopy_src);
#endif
};

struct Other
{
  CantCopy c;
};

void test()
{
    CantCopy c1;
    CantCopy c2;
    // fails: c3{c1};
    // fails: c2 = c1;
    Move_Value(&c1, &c2);
    Other o;
    Other o2;
    // also fails: o = o2;
}

void Move_Value(CantCopy *cantcopy_dest, const CantCopy *cantcopy_src)
{
    // do special stuff
    *cantcopy_dest = *cantcopy_src;
}
like image 55
PaulR Avatar answered Oct 16 '22 20:10

PaulR