Btw, I actually have an argument for returning a view=)

The ongoing c++20 ranges have exactly the same problem with the lifetime 
issues. For instance, this won’t compile:

auto results = std::vector<int>{1, 2, 3, 4, 5, 6}
     | std::views::filter([](int n){ return n % 2 == 0; })
     | std::views::transform([](int n){ return n * 2; });

But this will:
std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
auto results = numbers 
     | std::views::filter([](int n){ return n % 2 == 0; })
     | std::views::transform([](int n){ return n * 2; });

So, we’re returning back to the products and range-for-loop example:

const auto products = project->productsList();
auto results = products | std::views::transform(…);

==OR==

auto results = project->productsSpan() | std::views::transform(...);

To me, second looks much more intuitive than the first one.
And yes, it is possible to disable the && overload for a method that returns a 
view so the chained calls won’t compile 
(doesn’t solve all the other issues, though and is a bit verbose):

std::span<Product> Project::productsSpan() const & { return d->products; }
std::span<Product> Project::productsSpan() const && = delete;

auto results = createProject().products() | std::views::transform(…); // 
compile error, no need for Clazy!

Ivan

> 13 мая 2020 г., в 10:14, Иван Комиссаров <abba...@gmail.com> написал(а):
> 
> 
> 
>> 13 мая 2020 г., в 09:04, Lars Knoll <lars.kn...@qt.io 
>> <mailto:lars.kn...@qt.io>> написал(а):
>> 
>> The above example is rather weirdly constructed. 
>> 
>> But anyhow, those data lifetime issues when using views as return values 
>> extensively are a lot less obvious to spot when a human reads the code. APIs 
>> should be safe to use wherever possible, so that our users don’t have to 
>> worry about those things. This will lead to fewer bugs in the resulting code 
>> and faster development times. Trading that for some saved CPU cycles is in 
>> almost all cases (and yes there are exceptions in low level classes) a very 
>> bad deal.
> 
> Well, I can’t say that returning COW container is an easy thing to do. It’s a 
> trade-off between «safety» and «some CPU cycles». And I’d say it’s much 
> better if app crashes compared to the case where I have spent ages in 
> profiler fixing performance bugs introduced by the developers who doesn’t 
> really know how COW works (e.g. use operator[] instead of .at(), hidden 
> detaches)
> 
> There's already a «-Wclazy-range-loop» warning in Clazy about detaching COWs:
> 
> From Qbs code (which is written by the developers who are supposed to know 
> COW problems): 
> 
> 1. for (const QString &abi: rhs.split(QLatin1Char(' '))) // attempt to detach
> 
> 2. QList<ProductData> ProjectData::products() const { return d->products; }
>     for (const ProductData &p : project.products()) // oops, deep copy
> 
> And I can’t say that creating a variable on the stack before every for-loop 
> is an easier way for users (note, qAsConst doesn’t work for temporaries and 
> it should not).
> 
> The point is - there’s already a check in Clazy that does the similar check - 
> on can add a check for using a views from temporary.
> 
> And the lifetime issues only come into play when mixing views and non-views 
> approach:
> 
> Object myObject;
> auto view1 = myObject.getView()[42].getView(); // safe!
> auto view2 = myObject.getReference()[42].getView(); // safe!
> auto view3 = myObject.getCopy()[42].getView(); // not safe, copy is destroyed
> 
>> You can just as well argue the other way round. Returning a view requires 
>> the class to store the data in continuous memory. It can’t create it on the 
>> fly if asked.
> 
> How often is such a use-case, when you realize that you need to change the 
> simple getter to a container?
> 
> Why cannot you simply add a method with a new name in that case?
> 
> Am not really advocating for returning views, but it’s not that black and 
> white as you described, that’s a trade-off.
> What I am advocating for is that functions should take views where possible - 
> this is perfectly safe (you can pass temporaries into a view) and leads to 
> much easier code in some cases (users can pass unicode literals, 
> std::wstring, QVector<QChar> and so on).
> 
> Ivan

_______________________________________________
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to