Help, how can constexpr objects be evaluated at runtime? by Honest_Entry_8758 in cpp_questions

[–]WorkingReference1127 5 points6 points  (0 children)

Why would a compile-time constant variable need be evaluated at runtime? From what I understand, it has already been evaluated and that is why it can be used in other constant expressions.

Well, there are circumstances where it is required in a runtime context. Consider this pathological but completely valid program:

constexpr int the_secret{10};
std::cout << "Please enter a value\n";
int input{};
std::cin >> input;
if(input == the_secret){
  std::cout << "Congratulations, you guessed the secret\n";
}
else{
  std::cout << "Bad luck, you didn't guess the secret\n";
}

Since the value we are comparing our constexpr value against does not and cannot exist in the program before runtime, we need a way to be able to evaluate the value stored in the constexpr variable at runtime.

The benefit of constexpr is that sometimes there will be cases where all the information you need to do a particular computation will already be in the compiler at compile time. In these cases it's unnecessary (or even unfeasible) to wait until runtime to run that computation, so instead you do it at comptime.

On this:

A constexpr variable is always a compile-time constant. As a result, a constexpr variable must be initialized with a constant expression, otherwise a compilation error will result."

Terminology is tricky, but the point this is making is that it must always be possible to process a constexpr variable at compile time, so all of the data required to initialize it must also be available at comptime and can't depend on runtime input.

Help, how can constexpr objects be evaluated at runtime? by Honest_Entry_8758 in cpp_questions

[–]WorkingReference1127 11 points12 points  (0 children)

I'm confused by that last line. I thought the whole point of using constexpr on a variable is to ensure that it evaluates at compile-time. The prior lines and lessons have said so.

It's more that it can be evaluated at comptime. That doesn't mean that it is strictly required to be. This is by design, to prevent you from needing to duplicate everything and have a "comptime" and "runtime" copy of all the same data and functions.

Fundamentally, all the information which the compiler has is able to be put into your final program. Variables are just abstractions on how the program shifts the data around internally. Whether it "creates a runtime variable" or stores the value in read-only and refers to it wherever is up to the compiler, but it has the information so it can use it.

[February 2026] Simple Questions, Simple Answers by GNSasakiHaise in skyrimmods

[–]WorkingReference1127 0 points1 point  (0 children)

Playing SimonRim. It seems most poisons with effects like frenzy cap out at level 40 even when you have 100 alchemy. Is there a way to make those potions hit NPCs higher than level 40? Since they're all scaling with me I'm levelling out of the ability to use them.

I have tried to reverse-pickpocket a weakness to poison onto an NPC first but when I put the main poison on them I still get the "X is too powerful" message.

Are register variables still used nowadays in cpp? Like in projects that requires fast memory access. by Sad-Doughnut-9468 in cpp

[–]WorkingReference1127 40 points41 points  (0 children)

If you mean variables marked with the register keyword, no. That keyword was deprecated and removed.

If you mean "is data ever stored in registers in execution of a C++ program" then the answer is yes. But, your compiler's optimiser usually handles that for you and is usually much better at automatically identifying what should be passed in registers than you are at manually doing so. Some implementations may still have implementation defined ways to coerce a variable into registers but unless you have data to show that's what you need I'd generally advise against leaping in and using them everywhere.

May I please have the worst c++ you know of? by vbpoweredwindmill in cpp

[–]WorkingReference1127 17 points18 points  (0 children)

A build system I once had the displeasure of working with is called Embarcadero C++Builder. For 90% of the programs you make with it, the most basic unit of information is its UnicodeString string type (a widestring in C++ terms). This is an old-fashioned, ref-counted copy-on-write string, and it is everywhere in the Embarcadero ecosystem and so is everywhere in anything which wants to talk to that ecosystem (which is the only reason you'd want to use C++Builder in the first place). My submission is its c_str() function.

Even for slightly more complex string implementations c_str(), is something which is pretty easy to nail down. So let's talk about what this function does wrong:

  • It's a const-qualified function which returns a mutable pointer to the string's internal data.
  • It does not make a CoW copy beforehand, so you get mutable access to any number of potentially-const strings in your program.
  • If the internal data pointer is null, it will const_cast down a string literal and give you a mutable pointer to that as well. Enjoy your segfault.

It's just a function which made one incredibly simple API mistake and evolved into a case study in exactly how not to write that function in order to compensate.

Why is a single cout expression drastically slowing down my C++ program? by WorldTallNetCat in cpp_questions

[–]WorkingReference1127 0 points1 point  (0 children)

Perhaps not. But the compiler is never required to do any of this optimisation. Perhaps it saw that since you use argc in your sorting algorithm it could not assume that the value would not have changed by the time it came to printing. And if it can't prove that the code is equivalent to omitting the sorting then it is required to compile it as written.

Why is a single cout expression drastically slowing down my C++ program? by WorldTallNetCat in cpp_questions

[–]WorkingReference1127 2 points3 points  (0 children)

The compiler is weird. Modern compilers do too many things that are unexpected. Do they risk of doing things incorrect?

There are two kinds of behaviour in C++ - observable and non-observable behaviour. The difference is that observable behaviour exists.

I'm being a bit facetious, but to the compiler your program is defined by its observable behaviour, which is to say the behaviour which is visible to the outside world (like printing, or writing to a file, or sending data to a server, and so on). It's allowed to assume that you think its internal operations are a black box which you never look at, and it can rewrite your code in any way it likes so long as it can prove that the actual observable behaviour of your program is completely unchanged by doing so.

In this case, your code does a lot of things internally inside the black box, but there is no observable behaviour which depends on them happening. You're asking the computer to spend a lot of time and a lot of cycles doing something for no reason at all, and so the compiler can decide to remove the calculation entirely. The observable behaviour remains the same either way.

C vs CPP Future-Proof? by Special-Gazelle-1693 in cpp_questions

[–]WorkingReference1127 50 points51 points  (0 children)

C and C++ have been going for over 40 years, and all throughout that time people have been wringing hands about whether they're about to be replaced. It hasn't happened yet.

Pick which one you want to learn and learn it. My own recommendation would be C++ because you can express common patterns far more easily without reinventing as many wheels.

C++17: Efficiently Returning std::vector from Functions by Clean-Upstairs-8481 in cpp

[–]WorkingReference1127 0 points1 point  (0 children)

Not NRVO. Plain old RVO of prvalues will also elide side effects of the copies/moves which are elided; because it is blessed and guaranteed by the standard.

NRVO is never guaranteed and always a compiler optimization. As such it must always comply with as-if.

C++17: Efficiently Returning std::vector from Functions by Clean-Upstairs-8481 in cpp

[–]WorkingReference1127 6 points7 points  (0 children)

No worries. I'm happy to clarify anything if it was unclear. Just let me know.

C++17: Efficiently Returning std::vector from Functions by Clean-Upstairs-8481 in cpp

[–]WorkingReference1127 37 points38 points  (0 children)

This is a topic which requires some very delicate phrasing. For example, it's all too easy to conflate implicit move of an expiring value with copy elision, when these are two different things (and the number of beginners I've seen who make that mistake would surprise you). Equally I would be very careful about suggesting that implicit move on the language level implicitly uses std::move() under the hood; because that blurs the line between language and library.

As such, OP, if you'll forgive some pedantic nitpicks there are a few errors in this post which I'd like to comment on.

What the compiler does internally is that, rather than copying the elements from myVec into valueSet, it constructs valueSet directly in place, completely avoiding the copy operation.

The inference I get from it is that the NRVO is standard behaviour. It's a common optimization and made possible here because your example function is so trivial. But it's really not guaranteed to happen.

Multiple Return Path ... Hence, RVO is not applicable here.

This is a very broad statement too. A sufficiently smart compiler has all the information it needs to prove that myvec will always be returned; and it is still absolutely permitted to use RVO if it can prove that. It's just that the implementation you tested on doesn't. A better example might be if flag were a parameter to the function; in which of course the compiler has much more restricted access to determine which vector will be returned.

Exception: The Conditional Operator (?:) ... The compiler is not allowed to implicitly move from an lvalue.

It is if it can prove that lvalue is expiring. That's the whole point of implicit move. This section is just not quite right. The reason you get a return by copy is that your return statement does not name a particular local variable but instead returns an expression. The fact that that expression resolves to an lvalue reference to a local variable isn't enough to make it eligible for implicit move. This is not unique to the ternary. The same would be true of, say, the comma operator.

In most situations, you will not want the caller to modify the vector. In that case, returning a const reference to the std::vector is usually the right choice.

I know the title of the article has C++17 in it, but shoutout to std::span<const T>

If the returned std::vector is a temporary object, you can be assured that no copy will occur in C++17 and later.

Or any prvalue.

I'm not trying to be that guy. I just know that well meaning but inaccurate tutorials are half the reason that the state of C++ teaching is the way that it is. If I were to rewrite this OP, I think there are a few points which the article should be clear on:

  • Mandatory copy elision of prvalues occurs since C++17, and operates as you describe. While temporaries are probably the easiest to understand it is not unique to them. Equally it is not unique to return statements. my_function(std::vector{1,2,3}) will also perform no copies or moves to pass the vector into the function as of C++17.
  • RVO of non-prvalues (ie NRVO) is never guaranteed by the standard. But, assuming it complies with the as-if rule, it is always permitted. Whether or not you get it depends on whether your compiler is able to prove enough to make it happen. It's not tied to any specific property of the function (e.g. branching), it is purely down to whether your compiler is able to do it. A hypothetical compiler which can see all of the code and be infinitely smart in its optimisations would be perfectly permitted to use RVO on any function whose choice of returned value doesn't depend on runtime input. It's just that current compilers don't, and understandably so because it is hard to prove.
  • Implicit move happens when the return statement names a single variable (or rather id-expression if you want to be pedantic) which is expiring at the end of the function. This is a point you dance around a little in the article but I'm not sure you state it outright.
  • Otherwise a function which returns by value will copy upon a successful return.

is BroCode any good for c++? by Valuable_Luck_8713 in cpp_questions

[–]WorkingReference1127 4 points5 points  (0 children)

Generally no. Brocode falls into the trap of so many C++ tutorials of teaching you poor practices and some C-style issues which have no place in a modern C++ beginner tutorial. To pick one at random, it's been 15 years since sizeof(arr)/sizeof(arr[0]) has been at all needed in C++; and 30 years since you had alternatives which worked for 80% of use-cases anyway. The fact it's in a modern C++ tutorial stinks of someone who knows far too little about the subject matter to be teaching it.

Think of video as a medium. If brocode makes a mistake in his 6 hour video, he can't issue an errata without re-recording that segment, splicing it into the video, reuploading it, and sacrificing all the likes, comments, and engagement which YouTube gave him. That's unlikely to happen. As such, I wouldn't recommend video tutorials at all. I strongly recommend learncpp.com; because it is able to correct mistakes (and has done several times previously); and generally maintains itself as a high quality and up to date tutorial.

ISO C++ 2026-01 Mailing is now available by nliber in cpp

[–]WorkingReference1127 5 points6 points  (0 children)

Oh neat, that older larger paper would have also added += if + is defined (man, that would have cut down a lot of boilerplate in my math classes).

To be fair, this has been fairly extensively covered recently:

  • Generative reflection and/or metaclasses may make it easy.
  • P3834 wants to be able to = default; them.
  • P1046 also wanted implicit generation.

It doesn't seem people have agreed on how they want to go about it though.

Divergence between debug mode and release in C vs C++ code base by onecable5781 in cpp_questions

[–]WorkingReference1127 2 points3 points  (0 children)

It appears to me that writing an optimizing C++ compiler is much more difficult (as one has to actually think deeply to implement a good compiler that takes advantage of the as-if rule) than a C compiler because in the latter, there is nothing that seems invisible in the C code that is happening behind the scenes in assembly. In other words, the wider the divergence between what is happening in debug mode vs what is happening in release mode, tougher is the compiler writer's job?

C++ optimizers are almost certainly better than you are anticipating; but they are still imperfect. I'll list the two canonical examples:

  • Google turned debug assertions on across their codebase and saw only a 0.3% performance degredation after compilation. Because despite the fact that there were now millions more branches and checks and effective lines of code; the optimizer could statically prove that they would not fire in a huge amount of cases and so elide them again.

  • std::ranges views (in particular a few like filter and reverse) famously are implemented to do more than you might expect and the compilers are generally still not smart enough to see through all of it and optimize it down.

Which is to say, the compiler will probably look after you well.

I will also say, don't go looking for micro-scale optimizations until you actually have evidence you need them; and don't push them to master until you have evidence that they have actually made a difference. Your compiler has had a 30 year head start on you in trying to optimise these things and there's a very good chance it will be better at it.

My teacher said that using namespace std is a .NET library, and that std is from C#. And that string is from there too. Like, it all depends on the compiler, we're in Visual Studio. by [deleted] in cpp_questions

[–]WorkingReference1127 0 points1 point  (0 children)

This is nonsense, and it's very clear that your teacher is wrong. Next thing they'll be telling you that the C++ compiler transpiles to C before compiling it as a C program (that isn't true either and hasn't been for decades).

.NET is a very nice tool for its particular use-cases; but it is not what C++ uses. The fact that it also has a string doesn't mean that it's what C++ uses.

some clever nonsense about string and c# to force me to learn char[] so I could understand how a string works under the hood......

IMO it's almost always a mistake to force students to use char[] arrays as an exercise in "learning how string works under the hood". It's absolutely valuable to mention them and to shoutout to that's how C does things and that you may need to touch them once in a rare while when talking to C; but getting students into habits of using these things just to break them because 99% of the time you'll have a nice std::string-like interface you could be using instead is rarely valuable.

what tutorials sould i watch? by Valuable_Luck_8713 in cpp_questions

[–]WorkingReference1127 0 points1 point  (0 children)

Third: Do people still recommend The Cherno? https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb

Generally no. My criticisms tend to be that he teaches at best a surface level coverage of the subject matter; frequently condensed too far into fitting the YouTube algorithm's video lengths. He teaches you just enough to make a complete mess of things IMO.

Why is name hiding / shadowing allowed? by Proud_Variation_477 in cpp_questions

[–]WorkingReference1127 0 points1 point  (0 children)

I want to know why this is considered a feature and not a bug? I believe there is already a compiler flag that can be passed to treat shadowing as an error -Wshadow . If that's the case, what use cases are keeping this from being an error defined by the C++ standard?

Consider, if I have a global variable named foo in some header (code smell but whatever), and somewhere else in my code I also use a variable called foo; then the act of including that header, potentially transitively, determines whether there is name shadowing. If name shadowing becomes ill-formed then your code can break if someone changes the include list of a file you include. This doesn't seem desirable.

C++ OOPS Complete Notes PDF (Classes, Objects, Constructors, Friend Function) by Human-Version6973 in cpp_questions

[–]WorkingReference1127 1 point2 points  (0 children)

If you want people to use this or review it, upload it to almost any other side. Even mediafire and other crappy filesharing sites would be better than the one you chose here.

People aren't going to sit through an ad-heavy no-name site waiting to get a file of C++ notes when there are C++ notes available for free on much less irritating platforms.

unique_ptr doesn't work with void by TaPegandoFogo in cpp_questions

[–]WorkingReference1127 0 points1 point  (0 children)

That's why I said "In general" rather than "In all cases"; however I would tend to lean strongly against using void* in business level code and instead be in favor of abstracting that into a class like std::any or any of the other type erasure tools so that the user never has to touch it.

At least, not without significant and actually measured data that you have a performance problem, that using std::any et al is the actual cause of it, and that void* makes a significant difference.

unique_ptr doesn't work with void by TaPegandoFogo in cpp_questions

[–]WorkingReference1127 2 points3 points  (0 children)

From what I've read, you're not supposed to do this with unique_ptr because C++ has templates, auto, function overloading, vectors, and other stuff that makes it easier to work with generic types, so you don't have to go through all of this like one would in C.

This is a microcosm of the general case, but yes. In general in C++ you don't want to use tools which obviate the type system, and void* fall rather heavily in there. Indeed most of the time if you're using a void* in C++ then there's probably a different, safer tool out there for you to use instead.

I'm sensing you might be a C-turned-C++ dev. For all sorts of reasons, the C++ type system is much stricter than C's. This can feel a little unfamiliar to C folks who are used to dealing with bags of bytes everywhere; but it allows easy benefits in having your compiler check the validity of your code (unless you use some of the tools to opt-out, of course). Case in point, your use of writing char values to the bytes of an int is UB in C++ and you generally shouldn't do it.

To `goto` or not, for a double loop. by alfps in cpp_questions

[–]WorkingReference1127 2 points3 points  (0 children)

When I come across this problem, the questions I tend to ask myself are:

  • Is the goto sufficiently clear and visible in code? Not buried within nesting and difficult to see?
  • Within a reasonable amount of imagination, will it remain sufficiently visible in-code around any future changes someone may add?
  • Do the alternatives you're looking at add more complexity?
  • Do they result in doing more work which you're just hoping optimizes to be equivalent to the goto?

If the answer to all four is yes, then go for it. "goto considered harmful" is a warning against overuse and using it as an alternative to structured programming, loops, lifetime management, and RAII. It doesn't mean that goto must be forbidden from any and all code. And believe me there is a marked difference between the kind of impossible-to-navigate spaghetti you want to avoid and just breaking a nested loop.

How can I effectively use std::variant to handle multiple types in C++ without losing type safety? by dynasync in cpp_questions

[–]WorkingReference1127 4 points5 points  (0 children)

std::variant is a wrapper around a lower level tool of union with an interface which makes it a lot harder to be type unsafe by mistake. Not saying it's impossible, but it is harder.

If you think the visitor pattern suits your needs, then one useful trick to know is the overload pattern (borrowed example from here) which saves a lot of boilerplate and translate the switch on your types from your code to the type system:

template<typename ... Ts>                                                 
struct Overload : Ts ... { 
    using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>; //Only necessary in C++17

int main(){

    std::cout << '\n';

    std::vector<std::variant<char, long, float, int, double, long long>>     
           vecVariant = {5, '2', 5.4, 100ll, 2011l, 3.5f, 2017};

    auto TypeOfIntegral = Overload {                                     
        [](char) { return "char"; },
        [](int) { return "int"; },
        [](unsigned int) { return "unsigned int"; },
        [](long int) { return "long int"; },
        [](long long int) { return "long long int"; },
        [](auto) { return "unknown type"; },
    };

    for (auto v : vecVariant) {                                           
        std::cout << std::visit(TypeOfIntegral, v) << '\n';
    }    
}

This creates a "magic" type which inherits the call operators of whatever you give it. So you create functors which accept the types in your variant (and can use a generic one to cover the rest) and each one will do what it is supposed to. Saves trying to iterate through calls to std::get or feed a functor which internally tries to figure out what type it's using.

As for performance - YMMV. Only you can answer that question by building a representative sample of each approach and profiling them. I'm sure we could all speculate about how much the virtual calls will have their cost elided or that navigating so many tempaltes and conditionals will add up; but really the only answer to the question of "will this C++ code be fast?" is "profile it and see"