Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointers #14

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open

Pointers #14

wants to merge 8 commits into from

Conversation

mqnc
Copy link
Owner

@mqnc mqnc commented Jul 18, 2019

Just for commenting on code


class Registry
{
constexpr static std::size_t CHUNK{64};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused constant.

Suggested change
constexpr static std::size_t CHUNK{64};


class Registry
{
constexpr static std::size_t CHUNK{64};
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is never actually used

Copy link
Collaborator

@jkuebart jkuebart Jul 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-P
Screenshot 2019-07-19 at 14 20 51

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a horrendous injustice!

* point.
*/

Record& take(void* target)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it really be called take? I know it's "take a record" but my first intuition was "take this out of the registry" when we actually put something in.

* @param record The record to return.
*/

constexpr void put(Record& record)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we not actually deleting something from the registry rather than put something into it?
Is it more like the registry is a shelf of empty slots and if we register something, we take a record out and when we delete the record, we put it back in the registry?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current API uses the take()/put() nomenclature as you describe which I feel is consistent. Feel free to suggest a more intuitive alternative.

Record& take(void* target)
{
if (!mFreeRecord) {
mRecords.resize(1 + mRecords.size());
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not increase the storage by more than just one? Maybe double it like vector does or increase it by CHUNK? Or is this because we are still in the prototype phase and I should worry about other stuff?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::deque does this

return *this;
}

Target& operator =(Target&& target) noexcept(std::is_nothrow_move_assignable_v<Value>)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not make the record that is pointing to the moving-from target point to the moving-to target?

Copy link
Collaborator

@jkuebart jkuebart Jul 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make values wrapped inside Target<> behave like references:

auto a{Target<int>::create(0)};
auto b{Target<int>::create(1)};
b = a; // a and b are now 0
*b = 1; // what is a now?

What you suggest would make a == 1 at the end of this code. However, Target<> is intended to have value semantics.

Pointers provide the behaviour you describe:

auto a{Target<int>::create(0)};
auto b{Target<int>::create(1)};
auto aPtr{a.ptr()};
auto bPtr{b.ptr()};
bPtr = aPtr; // *aPtr and *bPtr both refer to a and are now 0
*bPtr = 1; // *aPtr and *bPtr both refer to a and are now 1

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am suggesting it for move construction/assignment, not for copy construction/assignment...
Or would it be inconsistent and confusing then?

Copy link
Collaborator

@jkuebart jkuebart Jul 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto a{Target<int>::create(0)};
auto b{Target<int>::create(1)};
b = a; // a and b are 0
*a = 1; // a is 1, b is 0
b = std::move(a); // a is indeterminate, b is 1
*a = 0; // a and b are 0

Yes, I think that's worse…

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there is a rule that by no means is a programmer allowed to touch a variable after it has been moved (see here https://en.wikipedia.org/wiki/Touch-move_rule)...
And we can even enforce that by setting the a-pointing record to nullpointer when we move from it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that leaves no way to access A, the destination of the assignment. And the effect of the assignment is only observable through A-Ptrs if you don't move the value to A.

While I don't think this can be made to work usefully for move-assignment, it is completely possible for move construction. In that case, there are no destination pointers or value to worry about, and the slot of the move-source can be taken over by the new target object.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aww! But that's already enough to make the vector thing work, which is everything I ever wanted! I'm glad we came to an agreement in the end.
By the way, at no point did I ever consider move assignment and move construction to be kind of the same thing, why would you even think that!

Copy link
Collaborator

@jkuebart jkuebart Jul 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work with std::vector, but is still sensitive to std::is_nothrow_move_constructible as described above, and can fail silently:

auto const t0{Target<int>::create(123)};
auto const t1{std::move(t0)};

performs copy-construction rather than move construction because t0 is const.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But should we still do it then? Although I like the feature, I don't know if the benefit in this one particular case is worth the fail-silently thing and also the inconsistency with move assignment...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that decision is up to the language designer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants