Intel® oneAPI DPC++/C++ Compiler
Talk to fellow users of Intel® oneAPI DPC++/C++ Compiler and companion tools like Intel® oneAPI DPC++ Library, Intel® DPC++ Compatibility Tool, and Intel® Distribution for GDB*
696 Discussions

Error using trivially copy-constructible data member of a non-trivially constructible parent class

giltirn
Novice
2,214 Views

For Intel(R) oneAPI DPC++/C++ Compiler 2021.2.0 (2021.x.0.20210323),  if one has a parent object that is not trivially copy-constructible, such as

std::pair<double, std::vector<double> > the_pair

then accessing the trivially copyable data member the_pair.first inside the kernel results in compile errors:

test.C:60:17: error: kernel parameter has non-trivially copy constructible class/struct type 'std::pair<double, std::vector<double>>'
data[i] = the_pair.first;

However adding an intermediate reference:

double &first_elem_ref = the_pair.first;

and accessing first_elem_ref inside the kernel is allowed. This suggests that the compiler is treating accesses to trivially copyable members by attempting to copy the entire object rather than just the member.

Attached is a simple demonstration. To use,

> make broken <-- error
> make working <--- no error

using the attached.

It seems to me that this should not be the intended behavior?

0 Kudos
1 Solution
giltirn
Novice
2,178 Views

Hi Rahul,

Thank you for your response. What I was trying to convey was that I believe the auto capture should only capture the actual data used in the kernel, in this case it should only copy the double "the_pair.first", but instead the compiler complains because it is trying to copy the entire object "the_pair" to the GPU, which contains a member which is not trivially copyable.

That being said, I have done a little research and it seems that the same behavior also applies for regular c++ lambdas, e.g.

struct my_struct{
  double a;
  my_struct() = default;
  my_struct(const my_struct &r) = delete;
};

template<typename T>
void lambda_apply(const T&l){
  l();
}

int main(void){
  my_struct d;
  d.a = 3.14;
  double test;
  double* test_p = &test;

  lambda_apply([=]{ *test_p = d.a; });

  return 0;
}

with g++ gives

test.cc:18:16: error: use of deleted function 'my_struct::my_struct(const my_struct&)'
18 | lambda_apply([=]{ *test_p = d.a; });
| ^~~~~~~~~~~~~~~~~~~~~
test.cc:4:3: note: declared here
4 | my_struct(const my_struct &r) = delete;
| ^~~~~~~~~
make: *** [Makefile:2: test] Error 1

Thus it seems that g++ also is trying to capture the entire object and not just the member. As such I will complain no further and will use the intermediate reference workaround if necessary.

Thanks,
Chris

 

 

View solution in original post

0 Kudos
3 Replies
RahulV_intel
Moderator
2,186 Views

Hi,

 

>>This suggests that the compiler is treating accesses to trivially copyable members by attempting to copy the entire object rather than just the member.

 

Could you please let me know how did you arrive at this conclusion? 

 

Alternatively, since you only require the data of the first pair to be read-only, instead of creating a reference variable, you may store the data in a temporary variable and assign that variable to data[i].

 

 

  double first_elem = the_pair.first;
  accelerator_for(i, 100, 1, {
#ifdef USE_BROKEN
      data[i] = the_pair.first;
#else
      data[i] = first_elem;
#endif
    });

 

 

 

Let us know if you face any issues.

 

Thanks,

Rahul

0 Kudos
giltirn
Novice
2,179 Views

Hi Rahul,

Thank you for your response. What I was trying to convey was that I believe the auto capture should only capture the actual data used in the kernel, in this case it should only copy the double "the_pair.first", but instead the compiler complains because it is trying to copy the entire object "the_pair" to the GPU, which contains a member which is not trivially copyable.

That being said, I have done a little research and it seems that the same behavior also applies for regular c++ lambdas, e.g.

struct my_struct{
  double a;
  my_struct() = default;
  my_struct(const my_struct &r) = delete;
};

template<typename T>
void lambda_apply(const T&l){
  l();
}

int main(void){
  my_struct d;
  d.a = 3.14;
  double test;
  double* test_p = &test;

  lambda_apply([=]{ *test_p = d.a; });

  return 0;
}

with g++ gives

test.cc:18:16: error: use of deleted function 'my_struct::my_struct(const my_struct&)'
18 | lambda_apply([=]{ *test_p = d.a; });
| ^~~~~~~~~~~~~~~~~~~~~
test.cc:4:3: note: declared here
4 | my_struct(const my_struct &r) = delete;
| ^~~~~~~~~
make: *** [Makefile:2: test] Error 1

Thus it seems that g++ also is trying to capture the entire object and not just the member. As such I will complain no further and will use the intermediate reference workaround if necessary.

Thanks,
Chris

 

 

0 Kudos
RahulV_intel
Moderator
2,138 Views

Hi,


Since your issue is resolved, I will go ahead and close this thread from my end. Intel will no longer monitor this thread. Further interactions on this thread will be considered community only.


Thanks,

Rahul


0 Kudos
Reply