2014-09-04 4 views
-3

Так как вы можете сделать std::unique_ptr<int> upi{new int}, я мгновенно запутался в том, как почему std::unique_ptr<int*> upi{new int[42]{}} не работает. Может ли кто-нибудь объяснить разницу между следующими фрагментами?Различия между int, int * и int [] с std :: unique_ptr

{ 
    std::unique_ptr<int> upi{new int[42]{}}; 
    upi.get()[0]; 
} 

// Doesn't work 
{ 
    std::unique_ptr<int> upi{new int[42]{}}; 
    upi[0]; 
} 

{ 
    std::unique_ptr<int[]> upi{new int[42]{}}; 
    upi.get()[0]; 
}  

{ 
    std::unique_ptr<int[]> upi{new int[42]{}}; 
    upi[0]; 
}  

// Doesn't work 
{ 
    std::unique_ptr<int*> upi{new int[42]{}}; 
    upi.get()[0]; 
}  

// Doesn't work  
{ 
    std::unique_ptr<int*> upi{new int[42]{}}; 
    upi[0]; 
} 

ошибки компилятора:

prog.cpp: In function ‘int main()’: 
prog.cpp:8:20: warning: value computed is not used [-Wunused-value] 
     upi.get()[0]; 
        ^
prog.cpp:14:12: error: no match for ‘operator[]’ (operand types are ‘std::unique_ptr<int>’ and ‘int’) 
     upi[0]; 
      ^
prog.cpp:19:20: warning: value computed is not used [-Wunused-value] 
     upi.get()[0]; 
        ^
prog.cpp:29:48: error: no matching function for call to ‘std::unique_ptr<int*>::unique_ptr(<brace-enclosed initializer list>)’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
prog.cpp:29:48: note: candidates are: 
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:176:2: note: template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&) 
    unique_ptr(auto_ptr<_Up>&& __u) noexcept; 
^
/usr/include/c++/4.8/bits/unique_ptr.h:176:2: note: template argument deduction/substitution failed: 
prog.cpp:29:48: note: mismatched types ‘std::auto_ptr<_Up>’ and ‘int*’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:169:2: note: template<class _Up, class _Ep, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Up, _Ep>&&) 
    unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept 
^
/usr/include/c++/4.8/bits/unique_ptr.h:169:2: note: template argument deduction/substitution failed: 
prog.cpp:29:48: note: mismatched types ‘std::unique_ptr<_Tp, _Dp>’ and ‘int*’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:160:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = int*; _Dp = std::default_delete<int*>] 
     unique_ptr(unique_ptr&& __u) noexcept 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:160:7: note: no known conversion for argument 1 from ‘int*’ to ‘std::unique_ptr<int*>&&’ 
/usr/include/c++/4.8/bits/unique_ptr.h:157:17: note: constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr(std::nullptr_t) [with _Tp = int*; _Dp = std::default_delete<int*>; std::nullptr_t = std::nullptr_t] 
     constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } 
       ^
/usr/include/c++/4.8/bits/unique_ptr.h:157:17: note: no known conversion for argument 1 from ‘int*’ to ‘std::nullptr_t’ 
/usr/include/c++/4.8/bits/unique_ptr.h:151:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer, typename std::remove_reference<_To>::type&&) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**; typename std::remove_reference<_To>::type = std::default_delete<int*>] 
     unique_ptr(pointer __p, 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:151:7: note: candidate expects 2 arguments, 1 provided 
/usr/include/c++/4.8/bits/unique_ptr.h:146:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer, typename std::conditional<std::is_reference<_Dp>::value, _Dp, const _Dp&>::type) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**; typename std::conditional<std::is_reference<_Dp>::value, _Dp, const _Dp&>::type = const std::default_delete<int*>&] 
     unique_ptr(pointer __p, 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:146:7: note: candidate expects 2 arguments, 1 provided 
/usr/include/c++/4.8/bits/unique_ptr.h:141:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**] 
     unique_ptr(pointer __p) noexcept 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:141:7: note: no known conversion for argument 1 from ‘int*’ to ‘std::unique_ptr<int*>::pointer {aka int**}’ 
/usr/include/c++/4.8/bits/unique_ptr.h:135:17: note: constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr() [with _Tp = int*; _Dp = std::default_delete<int*>] 
     constexpr unique_ptr() noexcept 
       ^
/usr/include/c++/4.8/bits/unique_ptr.h:135:17: note: candidate expects 0 arguments, 1 provided 
prog.cpp:30:20: warning: value computed is not used [-Wunused-value] 
     upi.get()[0]; 
        ^
prog.cpp:35:48: error: no matching function for call to ‘std::unique_ptr<int*>::unique_ptr(<brace-enclosed initializer list>)’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
prog.cpp:35:48: note: candidates are: 
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:176:2: note: template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&) 
    unique_ptr(auto_ptr<_Up>&& __u) noexcept; 
^
/usr/include/c++/4.8/bits/unique_ptr.h:176:2: note: template argument deduction/substitution failed: 
prog.cpp:35:48: note: mismatched types ‘std::auto_ptr<_Up>’ and ‘int*’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:169:2: note: template<class _Up, class _Ep, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Up, _Ep>&&) 
    unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept 
^
/usr/include/c++/4.8/bits/unique_ptr.h:169:2: note: template argument deduction/substitution failed: 
prog.cpp:35:48: note: mismatched types ‘std::unique_ptr<_Tp, _Dp>’ and ‘int*’ 
     std::unique_ptr<int*> upi{new int[42]{}}; 
               ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from prog.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:160:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = int*; _Dp = std::default_delete<int*>] 
     unique_ptr(unique_ptr&& __u) noexcept 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:160:7: note: no known conversion for argument 1 from ‘int*’ to ‘std::unique_ptr<int*>&&’ 
/usr/include/c++/4.8/bits/unique_ptr.h:157:17: note: constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr(std::nullptr_t) [with _Tp = int*; _Dp = std::default_delete<int*>; std::nullptr_t = std::nullptr_t] 
     constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } 
       ^
/usr/include/c++/4.8/bits/unique_ptr.h:157:17: note: no known conversion for argument 1 from ‘int*’ to ‘std::nullptr_t’ 
/usr/include/c++/4.8/bits/unique_ptr.h:151:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer, typename std::remove_reference<_To>::type&&) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**; typename std::remove_reference<_To>::type = std::default_delete<int*>] 
     unique_ptr(pointer __p, 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:151:7: note: candidate expects 2 arguments, 1 provided 
/usr/include/c++/4.8/bits/unique_ptr.h:146:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer, typename std::conditional<std::is_reference<_Dp>::value, _Dp, const _Dp&>::type) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**; typename std::conditional<std::is_reference<_Dp>::value, _Dp, const _Dp&>::type = const std::default_delete<int*>&] 
     unique_ptr(pointer __p, 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:146:7: note: candidate expects 2 arguments, 1 provided 
/usr/include/c++/4.8/bits/unique_ptr.h:141:7: note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = int*; _Dp = std::default_delete<int*>; std::unique_ptr<_Tp, _Dp>::pointer = int**] 
     unique_ptr(pointer __p) noexcept 
    ^
/usr/include/c++/4.8/bits/unique_ptr.h:141:7: note: no known conversion for argument 1 from ‘int*’ to ‘std::unique_ptr<int*>::pointer {aka int**}’ 
/usr/include/c++/4.8/bits/unique_ptr.h:135:17: note: constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr() [with _Tp = int*; _Dp = std::default_delete<int*>] 
     constexpr unique_ptr() noexcept 
       ^
/usr/include/c++/4.8/bits/unique_ptr.h:135:17: note: candidate expects 0 arguments, 1 provided 
prog.cpp:36:12: error: no match for ‘operator[]’ (operand types are ‘std::unique_ptr<int*>’ and ‘int’) 
     upi[0]; 
      ^
+10

не могли бы вы никогда никогда не говорить "не работает" снова? –

+0

'int' не' int * '. То, что у вас есть, не компилируется, а тем более «работает». – WhozCraig

+0

Это означает, что я получаю ошибку компилятора. – user4009226

ответ

6
std::unique_ptr<int> upi{new int[42]{}}; 

имеет неопределенное поведение. Вы назначаете память с помощью new[], а unique_ptr собирается позвонить по номеру delete, а не delete[], в свой деструктор.

upi[0]; 

не компилируется потому, что перегрузка unique_ptr::operator[] существует только для частичной специализации unique_ptr<T[]>.

std::unique_ptr<int*> upi{new int[42]{}}; 

не компилируется, потому что unique_ptr конструктор ожидает int**, но вы передаете ему int*. Если он скомпилировался, у него было бы неопределенное поведение по той же причине, что и в предыдущем случае.


Вы должны использовать

std::unique_ptr<int[]> upi{new int[42]{}}; 
upi.get()[0] = 0; // this works 
upi[0] = 0;  // and so does this 
0

Для того, чтобы использовать версию массива из unique_ptr, вы должны указать тип массива (т.е. int[] вместо int) в первом параметре шаблона, в противном случае вам вместо этого используют версию указателя.

int[] может деградировать в int*. Вы можете передать new int[] конструктору unique_ptr<int>, так как он принимает вход int*, но тогда вы не можете получить доступ к оператору upi[], потому что он не существует в этой версии , но только при использовании unique_ptr<int[]>.

+0

Как написать специализацию для версии указателя? – user4009226

+0

Если вы хотите использовать 'std :: unique_ptr ', вы должны предоставить конструктору 'int **', например 'std :: unique_ptr upi {new int * [42] {}};' Но конечно, это неправильно, потому что 'delete []' не будет использоваться. Вам придется использовать 'std :: unique_ptr upi {new int [42] {}};' вместо этого. –

+0

Чтобы сделать 'upi [0]' work for 'std :: unique_ptr ' – user4009226