Let's suppose I have a struct(or class) ObjectA
and it internally it has a large char[]. This object is created in thread 1. At some point, I want to go async by returning thread1
and pass the ObjectA
to another thread. Can I use std::move
to make ObjectA
a R-value and pass it as part of parameter to thread2
initialization function to avoid cost of copy? However, the memory of ObjectA
is allocated physically in thread1
's stack. And then thread1
unwind, all stack memory will be reclaimed, so I don't see how this can work without a physical copy step when thread1
hands over to thread2
.
Asked
Active
Viewed 165 times
-4

user4581301
- 33,082
- 7
- 33
- 54

Kenneth
- 561
- 1
- 5
- 13
-
If you have a large array as a member, move won't save you from copying it. Use `std::vector` instead which will benefit from move semantics. – François Andrieux Sep 29 '20 at 19:01
-
2Can you provide a code example of what you're trying to do please? Generally the following applies: [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – πάντα ῥεῖ Sep 29 '20 at 19:01
-
If the object can be destroyed before the other thread can move from it, then obviously it won't work. You need to synchronize access properly. – rustyx Sep 29 '20 at 19:09
-
@FrançoisAndrieux I understand that using vector will benefit because the data is actually living in heap and stack object only has reference. I admit I am really asking a rhetorical question. My contention is that c++'s complexity in copy/move/LR value are really unnecessary. It should follow Java or C# where complex object should only be allowed on heap and referenced by pointer or smart pointer. It will simplify a lot. This area is so confusing and easy to screw up without knowing. – Kenneth Sep 29 '20 at 19:41
-
@Kenneth I disagree completely that complex objects should only be on the heap, and you will find most C++ developers will agree. One good reason is performance. Dynamic memory allocation and freeing is significantly slower than using stack space, in addition to the synchronization issues of using a shared memory pool. Another is that C++ is conceptually very different from Object Oriented Languages like C# and Java because it favors value semantics. It makes sense on those language to have a abstraction between objects, their identifiers and handles and their representation. – François Andrieux Sep 29 '20 at 19:46
-
What is the purpose of saying that C++ should work more like Java or C#? C++ doesn't work like Java or C#, and never will, even if people wanted it to, because it needs to retain backwards-compatibility. – Jeremy Friesner Sep 29 '20 at 19:47
-
... In C++ there is no such distinction, an identifier is the unique identifier for an object, which has its own unique storage. When you do want shared handles, you can explicitly request them with pointers and references, but it is not the default behavior. That abstraction was not part of the language design as it does not match the goals of the language. One of C++'s key goals is to provide low level control, as near as possible to the hardware while still being portable. This is not one of the goals of Java or C#, which is why those languages are fundamentally different from C++. – François Andrieux Sep 29 '20 at 19:47
-
If you want behavior in C++ that more closely matches expectations you may have from C# or Java you can rely on `std::shared_ptr` which will allow you to have shared ownership pointers while managing memory for you, just like variables in those languages. – François Andrieux Sep 29 '20 at 19:50
-
`std::move` is not some kind of a sleight of hand that makes an object disappear in one place and pop back into reality somewhere else, as if by magic. Move semantics must be explicitly coded as move constructors and move operators. Without them a move becomes an ordinary copy. `std::vector` explicitly implements move semantics. Plain char arrays don't. – Sam Varshavchik Sep 29 '20 at 22:36
-
Often time, the object we create on the stack contains std containers such as vector, string etc whose actual content lives in heap. Wouldn't that cause the same perf concern (unless c++ manage them through a buffer pool of sort). – Kenneth Sep 30 '20 at 18:44
1 Answers
0
If ObjectA has a move constructor then you are over the first hurdle. Then next is how you give the thread2 the variable, if its a pointer or ref then you might have a problem.
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
is not going to work as you pass it a pointer to arg.
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );
The args are passed as rvalues.
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with std::ref or std::cref).
(untested code)
FuncA() {
ObjectA a;
std::thread t2(FuncB, std::move(a)); // if a has a move its moved else copied.
// all local variables are destroyed in reverse creation order.
// program crash if t2 is not saved elsewhere.
// a is destroyed.
}

Surt
- 15,501
- 3
- 23
- 39