Getters/Setters are useful sometimes, but aggregates are also useful.
If you have an aggregate, you should be willing to accept any data that matches the types of your data fields. If you want to maintain invariants (width>height) and assume it elsewhere in your code, you'll want accessors.
But code that doesn't assume invariants is often easier to work with and can even be less bug prone; manually maintaining invariants can get extremely hard, as messing up or compromising even once makes the invariant false.
Honestly, the biggest advantage of getters/setters is mocking (making test harnesses) and putting a breakpoint at access/modification. The costs in terms of code bulk and the like are real, and having more of the code you write not be boilerplate has value.
So a width/height field on a non-"live" rendered rect? Default to public data. A buffer used to store the data in a hand written optional<T>? Private data, and accessors.
Accessors should be used to reduce your own (or the code reader's) cognitive load. Write code with a purpose, and don't write code that doesn't have a purpose.
Now you'll still want to know how to write getters/setters, so practicing on stupid "rect width/height" cases has value. And learning the LSP problem that while a ReadOnly square is a kind of ReadOnly rect, a ReadWrite square is not a kind of ReadWrite rectangle might be best done via experience (or maybe not, as so many people experience it but don't learn the lesson).