2011-09-06 35 views
30

C++ xác định chức năng định dạng thời gian theo điều khoản của strftime, yêu cầu bản ghi "thời gian bị hỏng" struct tm. Tuy nhiên, ngôn ngữ C và C++ 03 không cung cấp cách an toàn cho luồng để có được bản ghi như vậy; chỉ có một chủ struct tm cho toàn bộ chương trình.C++ 11 thay thế cho localtime_r

Trong C++ 03, điều này ít nhiều là OK, bởi vì ngôn ngữ không hỗ trợ đa luồng; nó chỉ hỗ trợ các nền tảng hỗ trợ đa luồng, sau đó cung cấp các cơ sở như POSIX localtime_r.

C++ 11 cũng định nghĩa các tiện ích thời gian mới, giao diện với các phi vỡ xuống time_t loại, mà gì sẽ được sử dụng để khởi tạo lại toàn cầu struct tm. Nhưng lấy một số time_t không phải là vấn đề.

Tôi có thiếu điều gì đó hoặc thực hiện tác vụ này vẫn yêu cầu sự phụ thuộc vào POSIX không?

EDIT: Đây là một số mã giải pháp. Nó duy trì khả năng tương thích với môi trường đa luồng cung cấp ::localtime_r và môi trường một luồng chỉ cung cấp std::localtime. Nó có thể dễ dàng được điều chỉnh để kiểm tra các chức năng khác, chẳng hạn như posix::localtime_r hoặc ::localtime_s hoặc những gì bạn có.

namespace query { 
    char localtime_r(...); 

    struct has_localtime_r 
     { enum { value = sizeof localtime_r(std::declval< std::time_t * >(), std::declval< std::tm * >()) 
         == sizeof(std::tm *) }; }; 


    template< bool available > struct safest_localtime { 
     static std::tm *call(std::time_t const *t, std::tm *r) 
      { return localtime_r(t, r); } 
    }; 

    template<> struct safest_localtime<false> { 
     static std::tm *call(std::time_t const *t, std::tm *r) 
      { return std::localtime(t); } 
    }; 
} 
std::tm *localtime(std::time_t const *t, std::tm *r) 
    { return query::safest_localtime<query::has_localtime_r::value>().call(t, r); } 
+0

Bạn không thể chỉ quấn 'localtime' trong một hàm sử dụng mutex? Hoặc một số hình thức trọng lượng nhẹ hơn của khóa? Tôi không thấy POSIX được yêu cầu ở đây như thế nào. –

+7

@Nicol: Có, nhưng điều đó chỉ an toàn miễn là không ai khác cố gắng làm điều tương tự. Nói cách khác, nó hoạt động trong một chương trình, không phải trong một thư viện. – Potatoswatter

+0

Nhưng sau đó họ sẽ gọi một chức năng không an toàn với luồng từ mã luồng, vì vậy họ sẽ có được những gì họ xứng đáng nhận được. Bạn chỉ có thể phơi bày một chức năng cho họ để sử dụng, và nếu họ sử dụng một tiêu chuẩn C thay vào đó, sau đó họ nhận được hành vi không xác định. –

Trả lời

17

Bạn không thiếu gì cả.

Tiêu chuẩn C tiếp theo (dự kiến ​​ra mắt trong năm nay có lẽ) không có quy định tại Phụ lục K:

struct tm *localtime_s(const time_t * restrict timer, 
         struct tm * restrict result); 

Và chức năng mới này là chủ đề an toàn! Nhưng đừng quá hạnh phúc. Có hai vấn đề lớn:

  1. localtime_s là một tùy chọn phần mở rộng cho C11.

  2. Tham chiếu C++ 11 C99, chứ không phải C11. local_time_s không được tìm thấy trong C++ 11, tùy chọn hay không.

Cập nhật

Trong 4 năm kể từ khi tôi đã trả lời câu hỏi này, tôi cũng đã được thất vọng bởi việc thiết kế kém của các công cụ C++ trong lĩnh vực này. Tôi đã được thúc đẩy để tạo ra các công cụ hiện đại C++ để đối phó với điều này:

http://howardhinnant.github.io/date/tz.html

#include "tz.h" 
#include <iostream> 

int 
main() 
{ 
    using namespace date; 
    auto local_time = make_zoned(current_zone(), std::chrono::system_clock::now()); 
    std::cout << local_time << '\n'; 
} 

này chỉ ra cho tôi:

2015/10/28 14: 17: 31,980135 EDT

local_time là ghép nối của std::chrono::system_clock::time_pointtime_zone cho biết giờ địa phương.

Có các tiện ích để bẻ khóa các loại trường có thể đọc được, chẳng hạn như năm, tháng, ngày, giờ, phút, giây và giây.Dưới đây là một bài thuyết trình tập trung vào những người (phi múi giờ) mảnh:

https://www.youtube.com/watch?v=tzyGjOm8AKo

Tất cả điều này là tất nhiên an toàn (nó là hiện đại, C++) chủ đề.

+0

… Và họ đã đổi tên! Cảm ơn bạn về thông tin. Có thể, dù sao, để truy vấn liệu 'localtime_r' có khả dụng hay không và quay lại' localtime' nếu ngược lại. Vì vậy, có vẻ như tôi có thể có bánh của tôi và ăn nó quá, sau khi tất cả. – Potatoswatter