C++ 20 full features

Dear experts,

I will like to inquire about anyone having any idea when will the full features of C++ 20 be implemented in GCC and/or G++.

I am using the date functionality
1
2
3
4
5
6
7
std::string get_current_time_and_date()
{
    using namespace date;
    using namespace std::chrono;
    auto local = make_zoned(current_zone(), system_clock::now());
    return format("%F %T %Z", local) ;
}

However, when installing the date packages via conan, will hit an error with libcurl cross compilation from Linux to Win64.

Thus will like to convert to using fully C++20 chrono time zone (if the wait is not long)

PS: You can run the scripts in the link below. GCC11.1 will fail

https://en.cppreference.com/w/cpp/chrono/zoned_time

Thank You

**added ** There is no issue if I compile the Howard Hinnant date.h for the native machine. Can run properly. Only when cross compile will hit the libcurl issue
Last edited on
Using VS 2019/2022 promote the language standard to std:c++latest and that code snippet will compile. It will crash on execution for two of the time zones in the location list: "America/Tarasco_Bar" & "Europe/Laputa". No std::exception is thrown.

I'd guess the same issue is there for GCC.
Thanks George.

I intend not to use VS if possible.
GCC 11.1 does not support std::chrono::zoned_time yet

not sure about 11.2 but doubt so as no mention of zoned_time in changes
Otherwise I might consider using Ctime instead of chronos/Howard Hinnant date.h.

But I read that cons of ctime is
• Not type safe
• Not thread safe

I'm okay with type safe as I'm mainly using it as timestamp.
But what is the implication if it is not thread safe? (I will be implementing multi thread program)

Thank You

PS: I understand what is meant by thread safe. I will like to know the exact example of what will happens if I use ctime with multi thread. Can good programming avoid the non thread safe issue? Or there is no way to avoid it? Can I have specific examples?
Last edited on
Old function like ctime may have (for what ever reasion) static buffer. This is a problem with threads.

See:

https://cplusplus.com/reference/ctime/strftime/

According to this strftime(...) does not have this problem.
For displaying a struct tm data, there's also the stream put_time manipulator
http://www.cplusplus.com/reference/iomanip/put_time/

There's also localtime_s and ctime_s functions - if supported - which allow a pointer to a tm buffer - rather than returning a pointer to the in-built static.

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/ctime-s-ctime32-s-ctime64-s-wctime-s-wctime32-s-wctime64-s?view=msvc-170
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s?view=msvc-170
Last edited on
thanks coder777

will convert to ctime then since will not affect me.
and i will not concurrently change locale settings
Hi seeplus,

I guess I will try to avoid put_time.

As Concurrent access to the same stream object may cause data races, except for the standard stream objects.

For localtime_s and ctime_s, there is no mention of data concurrency, thus will not be taking the risk.

As don't want to spend lots of time debugging hard to trace concurrency issues.

Still thanks for the information
will convert to ctime then since will not affect me.
and i will not concurrently change locale settings
The main problem of ctime(...) is the return value. The resulting string is stored in a static buffer. Hence you may have sporadically invalid results when used in different threads. That should be avoided.
Don't use ctime(), localtime(), gmtime() etc in multi-thread code without first guarding against code concurrent-access until the result has been stored in thread safe storage.

Re put_time. This will use a stream, but this may be a local string stream in which case there are no issues as the string stream used is local to each thread.
I intend not to use VS if possible.

I wasn't suggesting you use VS, I was merely pointing out that one compiler requires using /std:c++latest to get some parts of C++20 working. Maybe GCC needs a similar "kick in the tuchas" as well.
hi thanks coder777,

Cos when reading the documentation that you sent me, I did not read anything about the resulting string is stored in a static buffer(probably I missed that) thus I assume there is no issue.

In that case I will avoid using ctime and use chronos instead. (Currently I am using date as timestamp for my Logger class. In my Logger class, there are a static map of Log class that will print the timestamp and other info to the log. )

Cos I don't want to spend days trying to debug issues caused by non thread safe where I can spend that time on more constructive things such as enhancing my program.

Below is my Logger class portion


Logger.h
------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <string>
#include <assert.h>
#include <SDL.h>
#include <map>
#include <mutex>
#include <memory>
#include "time.hpp"

enum LogLevel {DEBUG, INFO, ERROR, FATAL, MIN_LEVEL=DEBUG, MAX_LEVEL=FATAL};

class Log {
	private:
		std::string _fileName_;
		std::string _mode_;
		int _loggingLevel_;
		SDL_RWops* _file_;
		std::mutex _m_;

		void _initFile_();
		void _closeFile_();
		std::string _getLogLevelDesc_(int LogLevel);

	public:
		Log(std::string fileName, std::string mode = "a", int loggingLevel = DEBUG) : _fileName_(fileName), _mode_(mode), _loggingLevel_(loggingLevel) {
			_initFile_();
		}
		~Log() {
			_closeFile_();
		}
		void print(int logLevel, std::string msg);
};

class Logger {
	private:
		inline static std::map<std::string, std::unique_ptr<Log>> _logs_ = std::map<std::string, std::unique_ptr<Log>>();
	
	public:
		Logger() = default;
		~Logger() = default;
		static void log(int logLevel, std::string msg, std::string fileName = "logs.txt", std::string mode = "a", int loggingLevel = DEBUG);
};
#endif 


Logger.cpp
---------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <string>
#include <iostream>
#include "logger.hpp"

void Log::print(int logLevel, std::string msg) {
    /**
     * Writes the message to the log file 
     * 
     * @param logLevel The log type, must be one of the following "DEBUG", "INFO", "ERROR", "FATAL"
     * @param msg The message to print to the log files
     */

    assert(logLevel >= MIN_LEVEL && logLevel <= MAX_LEVEL);

    //static std::mutex io_mutex;

    //std::lock(_m_, _x_); // if more than one
    std::lock_guard<std::mutex> lk1(_m_, std::adopt_lock);
    //std::lock_guard<std::mutex> lk2(_x_, std::adopt_lock);

    if (_loggingLevel_ > logLevel || msg.empty()) {
        return;
    }

    std::string combinedMsg = get_current_time_and_date() + "     " + _getLogLevelDesc_(logLevel) + "     " +msg + "\n";

    {
        //std::lock_guard<std::mutex> lk(io_mutex);
        SDL_RWwrite( _file_, combinedMsg.c_str(), 1, combinedMsg.size() );
    }
}

std::string Log::_getLogLevelDesc_(int LogLevel) {
    switch(LogLevel) {
        case DEBUG : return "DEBUG";
        case INFO : return "INFO";
        case ERROR: return "ERROR";
        case FATAL: return "FATAL";
        default: return "UNKNOWN";
    };
}

void Log::_initFile_(){
    // clear the log file
    _file_ = SDL_RWFromFile(_fileName_.c_str(), "w");
    if(_file_==NULL) {
        std::cout << "Error creating log file " << _fileName_ <<". Program terminated abnormally.";
        exit(EXIT_FAILURE);
    } else {
        //Close file handler
        SDL_RWclose(_file_);
    }
    
    _file_ = SDL_RWFromFile(_fileName_.c_str(), _mode_.c_str());
    if(_file_==NULL) {
        std::cout << "Error creating log file " << _fileName_ <<". Program terminated abnormally.";
        exit(EXIT_FAILURE);
    } 
}

void Log::_closeFile_() {
    SDL_RWclose(_file_);
}

void Logger::log(int logLevel, std::string msg, std::string fileName, std::string mode, int loggingLevel) {
    if (!Logger::_logs_[fileName]) {
        Logger::_logs_[fileName] = std::make_unique<Log>(fileName, mode, loggingLevel);
    }

    Logger::_logs_[fileName]->print(logLevel, msg);
}

Last edited on
hi seeplus

I think I will avoid ctime as don't want to waste my time debugging non thread safe issues. Especially since my understanding of how ctime works is so limited and I don't want to waste my time understanding it.

Still thanks for all your help
Hi George, thanks for your input.

I think I will continue with using date.h (as I checked that gcc and clang does not support full features of time zone yet.)

Will stick with date.h and ignore the cross compiling. (After done, will boot up on Window and compile on Window - hopefully window supports conan without any changes to my codes.)

Thanks
PLEASE learn to use code tags, they make reading and commenting on source code MUCH easier.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

HINT: you can edit your post and add code tags.

Some formatting & indentation would not hurt either
Hi George,

Thanks for guiding me on how to format my post as source code.

Had done that.
There are more BB Code tags usable here, not just code tags. See 2nd link. The format grid next to the edit box is a handy way to use them.

FYI, the format buttons, as well as the preview button, do NOT work when creating a new topic. When editing the initial post or doing a follow up reply they do.

This is a well known bug, been the case for years. *shrug*

And don't bother trying to contact the site owner via the error reporting link. That's been done in the past and yet nothing has been done to correct it. Adding tags manually to a first topic post is almost 2nd nature to the regulars before posting, or editing it once posted.
Topic archived. No new replies allowed.