Как я могу найти, где конструктор копирования C ++ используется из-за ошибки компиляции? - PullRequest
5 голосов
/ 27 января 2012

Вкратце: есть ли способ изменить определение класса таким образом, чтобы он не компилировался в точке использования конструктора копирования независимо от того, где он используется?

IУ меня был очень большой проект, и я очищал некоторые определения классов.Есть класс, в котором я явно не хочу использовать конструкторы копирования (давайте проигнорируем, почему это делается для обсуждения), и в интересах безопасности я решил, что просто определю конструктор копирования как закрытый, а не какна самом деле реализовать его ... таким образом, он будет выдавать ошибку компиляции, если я попытаюсь использовать его где-нибудь.И вот, он прекрасно компилируется, но у меня есть ошибка компоновщика ... Реализация конструктора копирования не найдена!Предположительно это означает, что он где-то используется, но я не могу найти, где он используется.Это Visual Studio 2010, кстати.Итак, мой вопрос, есть ли способ, которым я могу изменить определение класса так, чтобы он не смог скомпилироваться в точке использования?

class Sample {
private:
    // not implemented
    Sample( const Sample& rhs );
    Sample& operator=( const Sample& rhs );
public:
    // implemented
    Sample();
...
};

Sample *samp1 = new Sample;
Sample *samp2 = new Sample( *samp1 ); // <<-- inaccessible here!  this works

Предположительно, так как я не нажимаю на ошибку компиляции, но нажимаюошибка компоновщика в том, что это означает, что сам класс (или друг) выполняет создание, созданное при копировании (поскольку это все, что будет иметь доступ к приватному конструктору), но я точно не могу его найти!

Ответы [ 6 ]

8 голосов
/ 27 января 2012

в C ++ 11 вы можете изменить определение на

class Sample {
private:
    // not implemented
    Sample( const Sample& rhs ) = delete;
    Sample& operator=( const Sample& rhs ) = delete;
public:
    // implemented
    Sample();
...
};

до C ++ 11, это обычно делается путем наследования от класса, который объявляет конструктор частного копирования, такой как boost:: NonCopyAble (вы можете просто скопировать этот класс, это всего несколько строк).В этом случае ваш класс (или любые друзья или дети) также не могут получить доступ к конструктору копирования, и это вызовет ошибку во время компиляции.

5 голосов
/ 27 января 2012

Наследование от класса, не подлежащего копированию:

class noncopyable
{
private:
    // not implemented
    noncopyable( const noncopyable& rhs );
    noncopyable& operator=( const noncopyable& rhs );
};


class Sample : private noncopyable {
private:
    // not implemented

    Sample( const Sample& rhs );
    Sample& operator=( const Sample& rhs );
public:
    // implemented
    Sample();

    // ...
};

Sample *samp1 = new Sample;
Sample *samp2 = new Sample( *samp1 ); // <<-- compile-time error

Это прекрасно работает, даже если у вас нет C ++ 11 (где упомянутый в другом месте метод delete, вероятно, предпочтителен).

3 голосов
/ 27 января 2012

Какую ошибку генерирует компоновщик?Если это LNK2019, должно быть легко отследить функцию, которая использует конструктор копирования:

MSDN говорит, что его формат:

неразрешенный внешний символ'ссылка в функции' функция '

Если посмотреть это сообщение об ошибке, вы можете найти метод, который вызывает неопределенный конструктор копирования.

1 голос
/ 27 января 2012

Вы пытаетесь получить модуль + номер строки во время компиляции? Попробуйте создать шаблонный конструктор копирования:

class A
{
  public:
  template< typename T >
  A( A const & )
  {
  }

  A()
  {
  }
};

int main( void )
{
 A a;
 A b( a ); // main.cpp(43) : error C2558: class 'A' : no copy constructor available or copy constructor is declared 'explicit'

 return ( 0 );
}
0 голосов
/ 27 января 2012

Если участник является личным, то вы должны уже получить ошибку по месту использования, если у него нет разрешения на доступ к закрытым членам.

Чтобы получить ту же ошибку в функциях, которые делает есть частный доступ, вы должны поместить объявление private-ctor там, к которому у них нет доступа, например, как частный член базового класса.

VS2010 пока не поддерживает его, нообъявление функции как удаленной также будет работать.

0 голосов
/ 27 января 2012

Насколько я помню, если вы объявите это inline, иногда вы получите ошибку компилятора, которая говорит, что он был объявлен как встроенный, но никогда не определен. Это было некоторое время назад и с gcc. YMMV.

[Показано не работать; оставляя это для потомков.]

...