owning_view class (C++ Standard Library)

A view that takes ownership of the elements in another range.

Syntax

template<range R>
    requires std::movable<R> && (!is-initializer-list<R>)
class owning_view : public ranges::view_interface<owning_view<R>>;

Template parameters

R
The type of the underlying range.

View characteristics

For a description of the following entries, see View class characteristics

Characteristic Description
Range adaptor views::all
Underlying range Must satisfy input_range or higher
Element type Same as the underlying range
View iterator category Same as the underlying range
Sized Only if the underlying range satisfies sized_range
Is const-iterable Only if the underlying range satisfies const-iterable
Common range Only if the underlying range satisfies common_range
Borrowed range Only if the underlying range satisfies borrowed_range

Members

Member functions Description
Constructors Construct an owning_view.
baseC++20 Get a reference to the owned range.
beginC++20 Get an iterator to the first element.
dataC++20 Get a pointer to the first element.
emptyC++20 Test whether the view is empty.
endC++20 Get the sentinel at the end of the view.
sizeC++20 Get the number of elements.
operator= Assign (move) the contents from another owning_view to this one.
Inherited from view_interface Description
backC++20 Get the last element.
frontC++20 Get the first element.
operator[]C++20 Get the element at the specified position.
operator boolC++20 Test whether the view isn't empty.

Remarks

The best way to create an owning_view is by using the views::all range adaptor. Range adaptors are the intended way to create view classes. The view types are exposed in case you want to create your own custom view type.

Even though this class owns its elements, it's not expensive to construct because the underlying range is moved using std::move().

This view is useful when you want a range that doesn't depend on the lifetime of the container providing the elements.

Requirements

Header: <ranges> (since C++20)

Namespace: std::ranges

Compiler Option: /std:c++20 or later is required.

Constructors

Create an instance of a owning_view.

1) owning_view() requires default_initializable<R> = default;
2) constexpr owning_view(R&& rg); 
3) owning_view(const owning_view& v) = delete; // no copy constructor 
4) owning_view(const owning_view&& v) = default; // move constructor

Parameters

rg
The range to move to the owning_view.

v
The owning_view to move to the new owning_view.

For information about template parameter types, see Template parameters.

Remarks

1) The default constructor creates a default-initialized owning_view.
2) Move constructs the owning_view from rg.
3) An owning_view can't be copied, only moved.
4) Construct the owning_view from another owning_view.

Example: owning_view

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
#include <utility>

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto myOwningView = std::views::all(std::move(v)); // create an owning_view from a moved vector
    std::cout << v.size() << '\n'; // outputs 0 because myOwningView now owns the elements
    std::cout << myOwningView.size() << '\n'; // outputs 10

    std::vector<int> v2 = {1,2,3,4,5};
    std::ranges::owning_view<std::vector<int>> ov2{std::move(v2)};
    std::cout << v2.size() << '\n'; // outputs 0 because ov2 now owns the elements
    std::cout << ov2.size() << '\n'; // outputs 5
}
0
10
0
5

base

Gets a reference to the underlying range.

1) constexpr R& base() & noexcept { return r_; }
2) constexpr const R& base() const & noexcept { return r_; }
3) constexpr R&& base() && noexcept { return std::move(r_); }
4) constexpr const R&& base() const && noexcept { return std::move(r_); }

Parameters

None.

Return value

A reference to the underlying range, call it rg.
For 1 & 2, the underlying range is returned via return rg;
For 3 & 4, the underlying range is returned via std::move(rg);

begin

Get an iterator to the first element in the view.

constexpr iterator_t<R> begin();
constexpr auto begin() const requires range<const R>;

Parameters

None.

Return value

An iterator pointing at the first element in the view:

Picture of a vector with the elements 10, 20, and 30. The first element contains 10 and is labeled begin(). The last element contains 30 and is labeled 'last element'. An imaginary box after the last element indicates the sentinel and is labeled end().

data

Get a pointer to the first element in the view.

constexpr auto data()
    requires std::contiguous_iterator<ranges::iterator_t<R>>;
constexpr auto data() const
    requires std::contiguous_iterator<ranges::iterator_t<const R>>;

Parameters

None.

Return value

A pointer to the first element in the view.

Remarks

The underlying owned range must satisfy contiguous_range.

empty

Test whether the view is empty.

constexpr bool empty();
constexpr bool empty() const;

Parameters

None.

Return value

Returns true if the underlying range has no elements. Otherwise, returns false.

end

Get the sentinel at the end of the view.

constexpr sentinel_t<R> end();
constexpr auto end() const requires range<const R>

Return value

The sentinel that follows the last element in the view:

Picture of a vector with the elements 10, 20, and 30. The first element contains 10 and is labeled begin(). The last element contains 30 and is labeled 'last element'. An imaginary box after the last element indicates the sentinel and is labeled end().

size

Get the number of elements in the view.

constexpr auto size() requires ranges::sized_range<R>;
constexpr auto size() const requires ranges::sized_range<const R>;

Parameters

None.

Return value

The number of elements in the view.

operator=

Assign (move) the contents from another owning_view to this one.

owning_view& operator=(owning_view&&) = default;

Parameters

The owning_view to assign (move) to this one.

Return value

*this

Remarks

An owning_view can't be copied, only moved.

Example: operator=

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v1 = {1,2,3};
    std::ranges::owning_view<std::vector<int>> ov1{std::move(v1)};
    
    std::vector<int> v2 = {4,5,6};
    std::ranges::owning_view<std::vector<int>> ov2{std::move(v2)};
    
    // operator=
    ov2 = std::move(ov1);

    // ov1 took ownership of v1, so v1 is empty
    // ov2 took ownership of v2, so v2 is empty
    // ov2 then took ownership of ov1, so ov1 is empty
    // ov2 now owns the elements 1, 2, 3

    std::cout << std::boolalpha << "v1.empty():" << v1.empty() << " ov1.empty():" << ov1.empty() << '\n'; // v1.empty():true ov1.empty():true
    std::cout << "v2.empty():" << v2.empty() << " ov2.size():" << ov2.size() << '\n'; // v2.empty():true ov2.size():3

    for (auto e : ov2)
    {
         std::cout << e << ' '; // 1 2 3
    }
}
v1.empty():true ov1.empty():true
v2.empty():true ov2.size():3
1 2 3

See also

<ranges>
all range adaptor
view classes