1
void thread_func(Color& r)
{
   //
}

void f()
{
   Color r(red_state);
   thread t(thread_func, r);
   t.join();
}

Simplified. I can't find anything online that matches this specific case (class object passed into non-member thread function). I've tried a few suggestions (adding '&', std::ref(r), using vectors, etc.), but I keep getting the following errors:

error: no type named 'type' in 'class std::result_of<void (*(Color*))(Color&)>'
error: use of deleted function 'Color::Color(const Color&)'

The latter makes me think it has something to do with the copy constructor, but I figured passing it in by reference shouldn't affect that? Any tips or feedback would be greatly appreciated.

JMoore
  • 95
  • 2
  • 8
  • AMA's example referenced in a comment below works. You can add your functionality to find out where it breaks. Obviously, your additional code (not shown here) uses copy construction, which is deleted in `Color` class. We cannot say you why if we do not see the whole code. Same as for the first error. – Daniel Langr Jan 15 '18 at 18:29
  • 1
    Possible duplicate of [Why does passing object reference arguments to thread function fails to compile?](https://stackoverflow.com/questions/8299545/why-does-passing-object-reference-arguments-to-thread-function-fails-to-compile) – AMA Jan 15 '18 at 18:29
  • You can have the thread's routine be a lambda which captures the object by reference. – Jon Deaton Jan 15 '18 at 18:58

2 Answers2

2

Use std::ref to pass by a reference. Namely:

thread t(thread_func, std::ref(r));

Learn about std::reference_wrapper to find out why: http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper.

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • 1
    @JMoore here's the minimal working [example](https://wandbox.org/permlink/3DJXXvMQHCMJJ9Es) – AMA Jan 15 '18 at 18:24
  • Ah, interesting. I suppose the error must lie somewhere in my class then... that closes this question at least. Thank you. – JMoore Jan 15 '18 at 18:29
  • @JMoore Most probably your `Color` class is missing a copy constructor. – AMA Jan 15 '18 at 18:37
  • @AMA Yes, but copy ctor is not requried in OP's code in case that `std::ref` is used. It's likely required somewhere inside code that is not shown. Maybe, in `thread_func` body, or... – Daniel Langr Jan 15 '18 at 18:41
1

When you try passing your object to the function as an argument, you are trying to pass it by value. Doing so with complex object and not just primitives causes C++ to call the copy constructor in order to construct a new object which is a copy of the object you passed.

Doing so with reference will result the same thing, as you see it has tried to call Color::Color(const Color&), which, as noted, got deleted.

You can try passing Color* (a pointer to Color) which should work, but this means you are going to use the exact same object, which can be dangerous if you are not careful with using it from two different threads. each change you will make to the object on the first thread will also apply for the second.

gkpln3
  • 1,317
  • 10
  • 24
  • Thanks for the warning. I'll give it a shot. – JMoore Jan 15 '18 at 18:23
  • This code should simulate what happens there https://wandbox.org/permlink/MArdSkuw2KBvhAUP Note that the copy constructors are deleted. – gkpln3 Jan 15 '18 at 18:31
  • I disagree. `thread`s constructor passes arguments by forwarding reference. Inside, they are copied (that's where copy ctor is required) and the copies are passed to `thread_func` by reference. There is no pass-by-value mechanism applied in this case. – Daniel Langr Jan 15 '18 at 18:39
  • References just exists in compile time, once it needs to pass the item to a different location (which cannot be on compile time) it has to create its own copy of the object (passing the value itself). thats when i ment by **by value** – gkpln3 Jan 15 '18 at 18:46
  • Doesn't matter. Your reasoning about calling copy ctor is wrong. Pass-by-value mechanism requires copy (or move) ctor, pass by reference (which is the case here) does not. – Daniel Langr Jan 15 '18 at 18:48
  • The requirement for copy ctor stems from the body of `thread`s constructor. This has nothing to do with passing its arguments. – Daniel Langr Jan 15 '18 at 18:50
  • By the way, your solution with pointers works, but it requires redefinition of `thread_func` (which may not be always feasible). Using `std::ref` does not require this and also does not use potentially dangerous pointers. – Daniel Langr Jan 15 '18 at 18:56
  • I agree passing the object by reference is preferable, But will work only if the compiler knows how to create a copy of your object (using the copy constructor), which in this case, as the error noted, is delete. – gkpln3 Jan 15 '18 at 18:58
  • No, passing the object by reference does not require copy constructor and does not make any copies. – Daniel Langr Jan 15 '18 at 19:16
  • Unless the receiver expects to receive a full object. A reference is more like an alias, it does not actually pass anything. – gkpln3 Jan 15 '18 at 19:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163212/discussion-between-daniel-langr-and-gkpln3). – Daniel Langr Jan 15 '18 at 20:25