if I do:
std::unique_ptr<int[]> uparr(new int[1984]);
and I pass uparr
to somebody without passing the 1984
to them can they see how many elements it has?
aka is there equivalent of vector's .size() for unique_ptr of array ?
if I do:
std::unique_ptr<int[]> uparr(new int[1984]);
and I pass uparr
to somebody without passing the 1984
to them can they see how many elements it has?
aka is there equivalent of vector's .size() for unique_ptr of array ?
No, there isn't. Dynamic arrays are a somewhat defective language feature. You'll essentially always want/need to pass the array length around separately (unless you have some kind of sentinel policy). So you might as well use std::vector
(if you don't mind the extra word for the capacity).
data
member function gives you a pointer to the elements –
Rocher No, the information is lost.
If you need to keep track of it, use a vector instead or if you really do not wants the extra services, write a small wrapper around an allocated array. You can for example look at the std::dynarray
proposal that was kicked off the c++1y standard.
unique_ptr
does not carry the size information. You could use vector
, but there are two issues:
You can wrap unique_ptr
with a size and make a custom container:
#include <cstddef> // for size_t
#include <cstdio> // for printf
#include <memory> // for unique_ptr
#include <utility> // for forward
template <class T>
struct DynArray final {
private:
std::unique_ptr<T[]> _data = nullptr;
std::size_t _size = 0;
public:
static DynArray ofSize(std::size_t const size) {
DynArray arr;
arr._data.reset(size ? new T[size] : nullptr);
arr._size = size;
return arr;
}
template <class... Args>
DynArray(Args&&... args)
: _data(sizeof...(Args)
? new T[sizeof...(Args)]{std::forward<Args>(args)...}
: nullptr),
_size{sizeof...(Args)} {}
DynArray(DynArray&& goner) noexcept
: _data{std::move(goner._data)}, _size(goner._size) {
goner._size = 0;
}
auto& operator=(DynArray&& goner) noexcept {
if (this != &goner) {
_data = std::move(goner._data);
this->_size = goner._size;
goner._size = 0;
}
return *this;
}
auto size() const noexcept { return _size; }
auto const* begin() const noexcept { return _data.get(); }
auto const* cbegin() const noexcept { return _data.get(); }
auto* begin() noexcept { return _data.get(); }
auto const* end() const noexcept { return begin() + _size; }
auto const* cend() const noexcept { return begin() + _size; }
auto* end() noexcept { return begin() + _size; }
auto const* data() const noexcept { return begin(); }
auto data() noexcept { return begin(); }
auto const& operator[](std::size_t i) const noexcept { return _data[i]; }
auto& operator[](std::size_t i) noexcept { return _data[i]; }
};
// Example usage
int main() {
auto arr = DynArray<int>{1, 2, 3, 4, 5};
for (auto elm : arr) printf("%d\n", elm);
auto arr2 = DynArray<char>::ofSize(3);
arr2[0] = 'A';
arr2[1] = 'B';
arr2[2] = 'C';
for (auto elm : arr2) printf("%c\n", elm);
}
absl::fixed_array<> is a somewhat-recent solution, which also has the benefit (over unique_ptr<T[]>) that it may inline small arrays instead of allocating them on the heap.
https://github.com/abseil/abseil-cpp/blob/master/absl/container/fixed_array.h
You pass this information along with the smart pointer, as an extra parameter, or within a std::tuple
or std::pair
. This is necessary because of c++ zero overhead principle.
© 2022 - 2024 — McMap. All rights reserved.