1

I have program that uses std::string, but memmove the std::string` instances.

It worked fine until gcc 5.1.

However this no longer works as of gcc 5.3. I think developers finally did SSO with internal pointer.

I will definitely fix that, but is there easy way to fix it with some define or pragma?

Code looks similar to this:

// MyClass have std::string inside
MyClass *a = malloc(MAX * sizeof(MyClass));
// ...
// placement new on a[0]
// ...
memmove(&a[1], &a[0], sizeof(MyClass));
// ...
process(a[1]);

This is old code, please do not comment about malloc usage.

I will refactor or switch to std::vector, but I want the code to work until I do so.

9
  • What you really should be doing is not to force the compiler to work with your code, but to refactor your code so it works with modern C++ compilers (and with that I mean everything from the last 15 years or so). That means not using malloc to allocate object, or use old C memory copying functions to copy the objects. Commented Dec 22, 2015 at 7:41
  • I want code to work until I refactor. Commented Dec 22, 2015 at 7:45
  • 1
    You can refactor with real placement new on older compiler where this code "works" Commented Dec 22, 2015 at 8:04
  • That has been undefined behavior before because your class is neither a POD in C++03 or trivially copyable in C++11. The compiler has every right to do what it wants in this case, and you cannot rely on any behavior, neither in gcc 5.3 or any other version. Commented Dec 22, 2015 at 8:20
  • 1
    @Nick First, it's undefined behavior. That means it may work, format your hard-drive or do anything. Not a good idea. But let's assume you have a string which is a (pointer, length) wrapper. The constructor allocate memory and the destructor deallocates it. Now you copy it with memcopy. You then have two objects with identical pointer values. Both destructors will deallocate the same pointer. IMHO, the C++ library should ban the old memcpy and add a new one which only works for POD (or TriviallyCopyable) types with std::enable_if. Commented Dec 22, 2015 at 17:03

1 Answer 1

1

You are experiencing effects of undefined behavior, but I think you know this. You cannot rely on the effects of byte-wise copying non-POD resp. not trivially copyable types, and the compiler is free to change that behavior.

I think it may be possible to define a safe overload for memmove with your class as arguments and use the copy-constructor inside it. I don't know if that is strictly legal, but you seem to be using the C-function instead of the C++ version in namespace std, so at least you are not changing namespace std which is not allowed.

void memmove(MyClass* a, MyClass* b, size_t)
{
    *a = *b;
}

Strictly speaking, I think this is still undefined behavior because 17.6.4.3 of the C++ standard specifies that

If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.

In addition, all names in C library are reserved names and shall not be used by the program (17.6.4.3.2). Practically, I think this will work.

You may need to compile with -fno-builtin to prevent gcc from replacing memmove globally. If it is illegal to overwrite the function, you can replace it dynamically with LD_PRELOAD.

This is a hack solution! Your code may still not work because the compiler makes the assumption that, when you memmove it is a POD/TriviallyCopyable object and uses that for some optimisation, e.g. by assuming that after the memmove, both objects are represented by identical bytes. This is broken when you re-implement memmove with the copy-constructor.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.