如何防止唯一指针重叠

huangapple go评论62阅读模式
英文:

How to prevent unique pointers from overlapping

问题

I'm trying to build a timer in C++.
In my Timer class there are two Date objects that hold a std::unique_ptr<struct tm> pointer.
After I std::move the second unique_ptr in the second Date object in the following piece of code, it points to the same memory address of the first one, effectively making the two objects represent the same time, even though they should be different because of the duration offset.

void Timer::start() {
    using namespace std;
    time_t localTime = time(nullptr);
    unique_ptr<struct tm> currentTime = static_cast<unique_ptr<struct tm>>(localtime(&localTime));
    startDate = Date(std::move(currentTime));

    time_t endTime = time(nullptr) + duration;
    unique_ptr<struct tm> timerEndTime = static_cast<unique_ptr<struct tm>>(localtime(&endTime));
    endDate = Date(std::move(timerEndTime));
}

The Date constructor being called is this:

Date::Date(std::unique_ptr<struct tm> time) : date(std::move(time)) {}

What am I doing wrong?

英文:

I'm trying to build a timer in C++.
In my Timer class there are two Date objects that hold a std::unique_ptr&lt;struct tm&gt; pointer.
After I std::move the second unique_ptr in the second Date object in the following piece of code, it points to the same memory address of the first one, effectively making the two objects represent the same time, even though they should be different because of the duration offset.

    using namespace std;
    time_t localTime = time(nullptr);
    unique_ptr&lt;struct tm&gt; currentTime = static_cast&lt;unique_ptr&lt;struct tm&gt;&gt;(localtime(&amp;localTime));
    startDate = Date(std::move(currentTime));

    time_t endTime = time(nullptr) + duration;
    unique_ptr&lt;struct tm&gt; timerEndTime = static_cast&lt;unique_ptr&lt;struct tm&gt;&gt;(localtime(&amp;endTime));
    endDate = Date(std::move(timerEndTime));

The Date constructor being called is this:

Date::Date(std::unique_ptr&lt;struct tm&gt; time) : date(std::move(time)) {}

What am I doing wrong?

答案1

得分: 4

这两个对象重叠并不奇怪,因为这是 std::localtime 应该工作的方式:

std::tm* localtime( const std::time_t *time );

返回值

成功时返回指向静态内部 std::tm 对象的指针,否则返回空指针。

如果您创建了一个包装 std::localtime 结果的 std::unique_ptr,然后尝试使用 delete 释放一个从未用 new 分配的对象,这是未定义行为。请写成这样:

std::time_t localTime = std::time(nullptr);
std::tm* currentTime = std::localtime(&localTime);
startDate = Date(*currentTime);

std::time_t endTime = std::time(nullptr) + duration;
std::tm* timerEndTime = std::localtime(&endTime);
endDate = Date(*timerEndTime);

您的 Date 构造函数应该接收一个 std::tmstd::tm const& 并以值方式存储它。如果您存储了一个指针,那么所有的 Date 对象都将包含指向静态内部对象的相同指针。

如何防止智能指针总体重叠?

这很容易做到,因为 std::unique_ptr 在大多数情况下都是防错的。只要您:

  • 立即接管指向 new 内存的指针,或者
  • 专门使用 std::make_unique,并且
  • 从不调用 std::unique_ptr::release()

... 您就不会意外使两个智能指针重叠。

英文:

It is unsurprising that the two objects overlap, because that is how std::localtime is supposed to work:

> cpp
&gt; std::tm* localtime( const std::time_t *time );
&gt;

> #### Return value
> pointer to a static internal std::tm object on success, or null pointer otherwise.

- See std::localtime on cppreference

If you create a std::unique_ptr that wraps the results of std::localtime, you will attempt to free an object with delete which was never allocated with new, and that is undefined behavior. Write:

std::time_t localTime = std::time(nullptr);
std::tm* currentTime = std::localtime(&amp;localTime);
startDate = Date(*currentTime);

std::time_t endTime = std::time(nullptr) + duration;
std::tm* timerEndTime = std::localtime(&amp;endTime);
endDate = Date(*timerEndTime);

Your Date constructor should be receiving a std::tm or std::tm const&amp; and store it by value. If you stored a pointer, then all Dates would contain the same pointer to a static internal object.

How do I prevent unique pointers from overlapping in general?

This is easy to do, because std::unique_ptr is more or less fool-proof. As long as you:

  • immediately take ownership of pointers to new memory, or
  • exclusively use std::make_unique, and
  • never call std::unique_ptr::release()

... you won't be able to accidentally make two smart pointers overlap.

huangapple
  • 本文由 发表于 2023年6月15日 17:24:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76481037.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定