Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Intel C++ Compiler 16.0.3 fails to compile valid code if copy constructor is deleted

Bastian_B_
New Contributor I
802 Views

The Intel C++ Compiler version 16.0.3 fails to compile the following code (The same code compiles fine with ICC 16.0.2):

class TestClass {
public:
  // default constructor, destructor, move constructor, move assignment operator
  TestClass() noexcept = default;
  ~TestClass() noexcept = default;
  TestClass(TestClass&&) noexcept = default;
  TestClass& operator=(TestClass&&) noexcept = default;

  // delete copy constructor and copy assignment operator
  TestClass(const TestClass&) noexcept = delete;
  TestClass& operator=(const TestClass&) noexcept = delete;

  TestClass Copy() const noexcept;

private:
  int fTestMember;
};

TestClass TestClass::Copy() const noexcept {

  TestClass copy;
  copy.fTestMember = fTestMember;
  // This should be possible by return value optimization - neither copy
  // constructor nor move constructor should be called!
  return copy;
}

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

  TestClass a;
  TestClass b = a.Copy();
  return 0;
}

This is on Linux with GCC 6.1.1 backend, but I have reproduced the same problem with GCC 4.9.3 and GCC 5.3.0. The compiler is invoked as follows:

icpc -std=c++11 -o test test.cc

The error message is:

test.cc(28): error: function "TestClass::TestClass(const TestClass &)" (declared at line 13) cannot be referenced -- it is a deleted function
   return copy;
          ^

compilation aborted for test.cc (code 2)

If I explicitly declare the move constructor myself like this:

--- test.cc     2016-05-05 17:15:10.314216763 +0200
+++ test.cc.new 2016-05-05 17:19:32.069354954 +0200
@@ -1,9 +1,12 @@
+#include <algorithm>
+#include <iostream>
+
 class TestClass {
 public:
   // default constructor, destructor, move constructor, move assignment operator
   TestClass() noexcept = default;
   ~TestClass() noexcept = default;
-  TestClass(TestClass&&) noexcept = default;
+  TestClass(TestClass&&) noexcept;
   TestClass& operator=(TestClass&&) noexcept = default;
 
   // delete copy constructor and copy assignment operator
@@ -16,6 +19,12 @@
   int fTestMember;
 };
 
+TestClass::TestClass(TestClass&& other) noexcept
+  : fTestMember(std::move(other.fTestMember)) {
+
+  std::cout << "Move constructor." << std::endl;
+}
+
 TestClass TestClass::Copy() const noexcept {
 
   TestClass copy;

Then the code compiles. But when the code is then execute, I don't get a "Move constructor." message on stdout so the move constructor was not called.

0 Kudos
6 Replies
Kittur_G_Intel
Employee
802 Views

Hi Bastian,
Thanks, I could reproduce the issue as well and it's a bug in the compiler. I'll file the issue with the developers and will keep you updated as soon the release with the fix is out. Appreciate your patience till then, thanks

Kittur

0 Kudos
andysem
New Contributor III
802 Views

Any news on this problem? I think I'm having the same problem with 18.0 update 1.

0 Kudos
Viet_H_Intel
Moderator
802 Views

Hi,

Can you please tell us which problem are you still seeing with 18.0 update 1? Is it the compilation error at line 28? or you don't see "Move constructor" message? if the later case, can you give us a test case which shows different results between icpc and g++?

Thanks,

Viet

0 Kudos
andysem
New Contributor III
802 Views

I'm having the problem with Boost.Atomic, it manifests as an error message like this:

error: the default constructor of "boost::atomics::atomic<T>" cannot be referenced -- it is a deleted function

where T is whatever type atomic<> is instantiated with, like char. The error points to a line like this:

boost::atomic< char > a;

Simplified atomic<> implementation looks like this:

template< typename T >
class atomic :
    public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type >
{
public:
    atomic() noexcept = default;
    explicit constexpr atomic(value_arg_type v) noexcept;
    atomic(atomic const&) = delete;
    atomic& operator= (atomic const&) = delete;
    atomic& operator= (atomic const&) volatile = delete;
};

The specializations of base_atomic also have similarly defined constructors. The full implementation is available here: https://github.com/boostorg/atomic (the atomic<> template definition is in https://github.com/boostorg/atomic/blob/develop/include/boost/atomic/detail/atomic_template.hpp).

My current workaround is to remove noexcept from the defaulted constructor declaration, see https://github.com/boostorg/atomic/blob/develop/include/boost/atomic/detail/atomic_template.hpp#L117. If you want to reproduce the problem, remove BOOST_INTEL from that condition.

I don't have the compiler myself, so I cannot experiment and reduce the original code to a smaller sample. The error was detected by one of our testers.

 

0 Kudos
Viet_H_Intel
Moderator
802 Views

Hi,

I tried the test case. It compiled successfully with 18.0 update 1.

$ icpc -std=c++11 t2.cpp -c -V

Intel(R) C++ Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.3.210 Build 20160415
Copyright (C) 1985-2016 Intel Corporation.  All rights reserved.

Edison Design Group C/C++ Front End, version 4.10 (Apr 16 2016 02:37:37)
Copyright 1988-2014 Edison Design Group, Inc.

t2.cpp(25): error: function "TestClass::TestClass(const TestClass &)" (declared at line 10) cannot be referenced -- it is a deleted function
     return copy;
            ^

compilation aborted for t2.cpp (code 2)
 

$ icpc -std=c++11 t2.cpp -c -V
Intel(R) C++ Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.1.163 Build                  20171018
Copyright (C) 1985-2017 Intel Corporation.  All rights reserved.

Edison Design Group C/C++ Front End, version 4.13 (Oct 19 2017 01:13:03)
Copyright 1988-2017 Edison Design Group, Inc.

$

Thanks,

Viet

0 Kudos
andysem
New Contributor III
802 Views

Can you try Boost.Atomic without the workaround?

0 Kudos
Reply