【问题标题】:Differences between int, int* and int[] with std::unique_ptr [closed]int、int* 和 int[] 与 std::unique_ptr 之间的区别 [关闭]
【发布时间】:2014-10-29 15:35:17
【问题描述】:

既然你可以做到std::unique_ptr<int> upi{new int},我立刻就对为什么std::unique_ptr<int*> upi{new int[42]{}} 不起作用感到困惑。有人能解释一下以下sn-ps之间的区别吗?

{
    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];
            ^

【问题讨论】:

  • 你能不能再说“不工作”?
  • int 不是int*。你所拥有的不是编译,更不用说“工作”了。
  • 这意味着我得到了编译器错误。s
  • 总是发布您遇到的实际错误,并显示哪些行产生了错误。
  • +1 用于发布错误。为了进一步改进,请稍微整理一下错误。比如第一个警告:你明白了吗?也许通过将错误放在代码旁边来将错误与代码联系起来。

标签: c++ pointers c++11 unique-ptr


【解决方案1】:
 std::unique_ptr<int> upi{new int[42]{}};

具有未定义的行为。您正在使用new[] 分配内存,而unique_ptr 将在其析构函数中调用delete,而不是delete[]

upi[0];

无法编译,因为 unique_ptr::operator[] 重载只存在于 unique_ptr&lt;T[]&gt; 部分特化。

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

【讨论】:

    【解决方案2】:

    为了使用unique_ptr的数组版本,您必须在第一个模板参数中指定一个数组类型(即int[]而不是int),否则您将使用指针版本。

    int[] 可以降级为int*。您可以将new int[] 传递给unique_ptr&lt;int&gt; 的构造函数,因为它需要int* 作为输入,但是您不能访问upi[] 运算符,因为它在unique_ptr 的那个版本中不存在,只有在使用@ 时改为 987654331@。

    【讨论】:

    • 如何为指针版本编写特化?
    • 如果你想使用std::unique_ptr&lt;int*&gt;,你必须给构造函数提供一个int**,比如std::unique_ptr&lt;int*&gt; upi{new int*[42]{}};,但是这当然是错误的,因为delete[]不会被使用。您必须改用std::unique_ptr&lt;int*[]&gt; upi{new int[42]{}};
    • upi[0]std::unique_ptr&lt;int&gt;工作
    • upi[] 不适用于std::unique_ptr&lt;int&gt;,因为operator[] 在该版本中根本不存在。甚至不要尝试使用它。无论如何,将int[] 放入unique_ptr&lt;int&gt; 是错误的。您必须改用std::unique_ptr&lt;int[]&gt;。这就是它的用途。不要规避这一点。
    猜你喜欢
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    相关资源
    最近更新 更多