主頁 > 後端開發 > C++98/11/17運算式類別

C++98/11/17運算式類別

2020-09-13 12:17:32 後端開發

目標

以下代碼能否編譯通過,能否按照期望運行?(點擊展開)
#include <utility>
#include <type_traits>

namespace cpp98
{

struct A { };
A func() { return A(); }

int main()
{
    int i = 1;
    i = 2;
    // 3 = 4;
    const int j = 5;
    // j = 6;
    i = j;
    func() = A();
    return 0;
}

}

namespace cpp11
{

#define is_lvalue(x)  std::is_lvalue_reference<decltype((x))>::value
#define is_prvalue(x) !std::is_reference<decltype((x))>::value
#define is_xvalue(x)  std::is_rvalue_reference<decltype((x))>::value
#define is_glvalue(x) (is_lvalue(x) || is_xvalue(x))
#define is_rvalue(x)  (is_xvalue(x) || is_prvalue(x))

void func();
int non_reference();
int&& rvalue_reference();
std::pair<int, int> make();

struct Test
{
    int field;
    void member_function()
    {
        static_assert(is_lvalue(field), "");
        static_assert(is_prvalue(this), "");
    }
    enum Enum
    {
        ENUMERATOR,
    };
};

int main()
{
    int i;
    int&& j = std::move(i);
    Test test;

    static_assert(is_lvalue(i), "");
    static_assert(is_lvalue(j), "");
    static_assert(std::is_rvalue_reference<decltype(j)>::value, "");
    static_assert(is_lvalue(func), "");
    static_assert(is_lvalue(test.field), "");
    static_assert(is_lvalue("hello"), "");

    static_assert(is_prvalue(2), "");
    static_assert(is_prvalue(non_reference()), "");
    static_assert(is_prvalue(Test{3}), "");
    static_assert(is_prvalue(test.ENUMERATOR), "");

    static_assert(is_xvalue(rvalue_reference()), "");
    static_assert(is_xvalue(make().first), "");

    return 0;
}

}

namespace reference
{

int&& rvalue_reference()
{
    int local = 1;
    return std::move(local);
}

const int& const_lvalue_reference(const int& arg)
{
    return arg;
}

int main()
{
    auto&& i = rvalue_reference();        // dangling reference
    auto&& j = const_lvalue_reference(2); // dangling reference
    int k = 3;
    auto&& l = const_lvalue_reference(k);
    return 0;
}

}

namespace auto_decl
{

int non_reference() { return 1; }
int& lvalue_reference() { static int i; return i; }
const int& const_lvalue_reference() { return lvalue_reference(); }
int&& rvalue_reference() { static int i; return std::move(i); }

int main()
{
    auto [s1, s2] = std::pair(2, 3);
    auto&& t1 = s1;
    static_assert(!std::is_reference<decltype(s1)>::value);
    static_assert(std::is_lvalue_reference<decltype(t1)>::value);

    int i1 = 4;
    auto i2 = i1;
    decltype(auto) i3 = i1;
    decltype(auto) i4{i1};
    decltype(auto) i5 = (i1);
    static_assert(!std::is_reference<decltype(i2)>::value, "");
    static_assert(!std::is_reference<decltype(i3)>::value, "");
    static_assert(!std::is_reference<decltype(i4)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(i5)>::value, "");

    auto n1 = non_reference();
    decltype(auto) n2 = non_reference();
    auto&& n3 = non_reference();
    static_assert(!std::is_reference<decltype(n1)>::value, "");
    static_assert(!std::is_reference<decltype(n2)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(n3)>::value, "");

    auto l1 = lvalue_reference();
    decltype(auto) l2 = lvalue_reference();
    auto&& l3 = lvalue_reference();
    static_assert(!std::is_reference<decltype(l1)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(l2)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(l3)>::value, "");

    auto c1 = const_lvalue_reference();
    decltype(auto) c2 = const_lvalue_reference();
    auto&& c3 = const_lvalue_reference();
    static_assert(!std::is_reference<decltype(c1)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(c2)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(c3)>::value, "");

    auto r1 = rvalue_reference();
    decltype(auto) r2 = rvalue_reference();
    auto&& r3 = rvalue_reference();
    static_assert(!std::is_reference<decltype(r1)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(r2)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(r3)>::value, "");

    return 0;
}

}

namespace cpp17
{

class NonMoveable
{
public:
    int i = 1;
    NonMoveable(int i) : i(i) { }
    NonMoveable(NonMoveable&&) = delete;
};

NonMoveable make(int i)
{
    return NonMoveable{i};
}

void take(NonMoveable nm)
{
    return static_cast<void>(nm);
}

int main()
{
    auto nm = make(2);
    auto nm2 = NonMoveable{make(3)};
    // take(nm);
    take(make(4));
    take(NonMoveable{make(5)});
    return 0;
}

}

int main()
{
    cpp98::main();
    cpp11::main();
    reference::main();
    auto_decl::main();
    cpp17::main();
}

C++98運算式類別

每個C++運算式都有一個型別:42的型別為intint i;(i)的型別為int&,這些型別落入若干類別中,在C++98/03中,每個運算式都是左值或右值,

左值(lvalue)是指向真實儲存在記憶體或暫存器中的值的運算式,“l”指的是“left-hand side”,因為在C中只有lvalue才能寫在賦值運算子的左邊,相對地,右值(rvalue,“r”指的是“right-hand side”)只能出現在賦值運算子的右邊,

有一些例外,如const int i;i雖然是左值但不能出現在賦值運算子的左邊,到了C++,型別別的rvalue卻可以出現在賦值運算子的左邊,事實上這里的賦值是對賦值運算子函式的呼叫,與基本型別的賦值是不同的,

lvalue可以理解為可取地址的值,變數、對指標解參考、對回傳型別為參考型別的函式的呼叫等,都是lvalue,臨時物件都是rvalue,包括字面量和回傳型別為非參考型別的函式呼叫等,字串字面量是個例外,它屬于不可修改的左值,

賦值運算子左邊需要一個lvalue,右邊需要一個rvalue,如果給它一個lvalue,該lvalue會被隱式轉換成rvalue,這個程序是理所當然的,

動機

C++11引入了右值參考和移動語意,函式回傳的右值參考,顧名思義,應該表現得和右值一樣,但是這會破壞很多既有的規則:

  • rvalue是匿名的,不一定有存盤空間,但右值參考指向記憶體中的具體物件,該物件還要被維護著;

  • rvalue的型別是確定的,必須是完全型別,靜態型別與動態型別相同,而右值參考可以是不完全型別,也可以支持多型;

  • 非型別別的rvalue沒有cv修飾(constvolatile),但右值參考可以有,而且修飾符必須保留,

這給傳統的lvalue/rvalue二分法帶來了挑戰,C++委員會面臨選擇:

  • 維持右值參考是rvalue,添加一些特殊規則;

  • 把右值參考歸為lvalue,添加一些特殊規則;

  • 細化運算式類別,

上述問題只是冰山一角;歷史選擇了第三種方案,

C++11運算式類別

C++11提出了運算式類別(value category)的概念,雖然名叫“value category”,但類別劃分的是運算式而不是值,所以我從標題開始就把它譯為“運算式類別”,C++標準定義運算式為:

An expression is a sequence of operators and operands that specifies a computation. An expression can result in a value and can cause side effects.

每個運算式都是三種類別之一:左值(lvalue)、消亡值(xvalue)和純右值(prvalue),稱為主類別,還有兩種混合類別:lvalue和xvalue統稱范左值(glvalue),xvalue和prvalue統稱右值(rvalue),

#define is_glvalue(x) (is_lvalue(x) || is_xvalue(x))
#define is_rvalue(x)  (is_xvalue(x) || is_prvalue(x))

C++11對這些類別的定義如下:

  • lvalue指定一個函式或一個物件;

  • xvalue(eXpiring vavlue)也指向物件,通常接近其生命周期的終點;一些涉及右值參考的運算式的結果是xvalue;

  • gvalue(generalized lvalue)是一個lvalue或xvalue;

  • rvalue是xvalue、臨時物件或它們的子物件,或者沒有關聯物件的值;

  • prvalue(pure rvalue)是不是xvalue的rvalue,

這種定義不是很清晰,具體來講,lvalue包括:(點擊展開)
  • 變數、函式、資料成員的名字,包括右值參考型別的變數也是lvalue;

    int i;
    int&& j = std::move(i);
    static_assert(is_lvalue(j), "");
    static_assert(std::is_rvalue_reference<decltype(j)>::value, "");
    
  • 函式呼叫或多載運算子運算式,其回傳型別為左值參考型別,或函式的右值參考型別;

  • 內置賦值、復合賦值、前置自增、前置自減運算子運算式;

  • 內置陣列下標運算式a[n]p[n]a為陣列型別,p為指標型別),a是一個陣列lvalue;

  • a.m,除非m是列舉成員,或非靜態成員函式,或a是rvalue且m是非參考型別的非靜態資料成員;

  • p->m,除非m是列舉成員,或非靜態成員函式;

  • a.*mpa是一個lvalue,mp是資料成員指標;

  • p->*mpmp是資料成員指標;

  • 逗號運算式,第二個運算元是lvalue;

  • 條件運算子a ? b : c,這里有非常復雜的規則,舉其中一例,當bc是相同型別的lvalue時;

  • 字串字面量;

  • 顯式轉換為左值參考型別或函式的右值參考型別,

lvalue的性質:

  • 與glvalue相同;

  • 內置取地址運算子可以作用于lvalue;

  • 可修改的lvalue可以出現在內置賦值運算子的左邊;

  • 可以用來初始化一個左值參考,

prvalue包括:
  • 除字串以外的字面量;

  • 函式呼叫或多載運算子運算式,其回傳型別為非參考型別;

  • 內置算術運算、邏輯運算、比較運算、取地址運算子運算式;

  • a.mp->mm是列舉成員或非靜態成員函式(見下);

  • a.*mpp->*mpmp是成員函式指標;

  • 逗號運算式,第二個運算元是rvalue;

  • 條件運算子a ? b : c的部分情況,如bc是相同型別的prvalue;

  • 顯式轉換為非參考型別;

  • this指標;

  • 列舉成員;

  • 非型別模板引數,除非它是左值參考型別;

  • lambda運算式,

prvalue的性質:

  • 與rvalue相同;

  • 不能是多型的;

  • 非型別別且非陣列的prvalue沒有cv修飾符,即使寫了也沒有;

  • 必須是完全型別;

  • 不能是抽象型別或其陣列,

xvalue包括:
  • 函式呼叫或多載運算子運算式,其回傳型別為右值參考型別;

  • 內置陣列下標運算式a[n]a是一個陣列rvalue;

  • a.ma是rvalue且m是非參考型別的非靜態資料成員;

  • a.*mpa是一個rvalue,mp是資料成員指標;

  • 條件運算子a ? b : c的部分情況,如bc是相同型別的xvalue,

xvalue的性質;

  • 與rvalue相同;

  • 與glvalue相同,

glvalue的性質:

  • 可以隱式轉換為prvalue;

  • 可以是多型的;

  • 可以是不完全型別,

rvalue的性質:

  • 內置取地址運算子不能作用于rvalue;

  • 不能出現在內置賦值或復合賦值運算子的左邊;

  • 可以系結給const左值參考(見下);

  • 可以用來初始化右值參考(見下);

  • 如果一個函式有右值參考引數和const左值參考引數兩個多載,傳入一個rvalue時,右值參考的那個多載被呼叫,

還有一些特殊的分類:

  • 對于非靜態成員函式mf及其指標pmfa.mfp->mfa.*pmfp->*pmf都被歸類為prvalue,但它們不是常規的prvalue,而是pending(即將發生的) member function call,只能用于函式呼叫;

  • 回傳void的函式呼叫、向void的型別裝換和throw陳述句都是void運算式,不能用于初始化參考或函式引數;

  • C++中最小的尋址單位是位元組,因此位域不能系結到非const左值參考上;const左值參考和右值參考可以系結位域,它們指向的是位域的一個拷貝,

終于把5個類別介紹完了,運算式可以分為lvalue、xvalue和prvalue三類,lvalue和prvalue與C++98中的lvalue和rvalue類似,而xvalue則完全是為右值參考而生,兼有glvalue與rvalue的性質,除了這種三分類法外,運算式還可以分為lvalue和rvalue兩類,它們之間的主要差別在于是否可以取地址;還可以分為glvalue和prvalue兩類,它們之間的主要差別在于是否存在物體,glvalue有物體,因而可以修改原物件,xvalue常被壓榨剩余價值,

參考系結

我們稍微岔開一會,來看兩個與運算式分類相關的特性,

參考系結有以下型別:

  • 左值參考系結lvalue,cv修飾符只能多不能少;

  • 右值參考可以系結rvalue,我們通常不給右值參考加cv修飾符;

  • const左值參考可以系結rvalue,

左值參考系結lvalue天經地義,沒什么需要關照的,但rvalue都是臨時物件,系結給參考就意味著要繼續用它,它的生命周期會受到影響,通常,rvalue的生命周期會延長到系結參考的宣告周期,但有以下例外:

  • return陳述句回傳的臨時物件在return陳述句結束后即銷毀,這樣的函式總是會回傳一個空懸參考(dangling reference);

  • 系結到初始化串列中的參考的臨時物件的生命周期只延長到建構式結束——這是個缺陷,在C++14中被修復;

  • 系結到函式引數的臨時物件的生命周期延長到函式呼叫所在運算式結束,把該引數作為參考回傳會得到空懸參考;

  • 系結到new運算式中的參考的臨時物件的生命周期只延長到包含new的運算式的結束,不會跟著那個物件,

簡而言之,臨時變數的生命周期只能延長一次,

#include <utility>

int&& rvalue_reference()
{
    int local = 1;
    return std::move(local);
}

const int& const_lvalue_reference(const int& arg)
{
    return arg;
}

int main()
{
    auto&& i = rvalue_reference();        // dangling reference
    auto&& j = const_lvalue_reference(2); // dangling reference
    int k = 3;
    auto&& l = const_lvalue_reference(k);
}

rvalue_reference回傳一個指向區域變數的參考,因此i是空懸參考;2系結到const_lvalue_reference的引數arg上,函式回傳后延長的生命周期達到終點,因此j也是懸空參考;k在傳參的程序中根本沒有臨時物件創建出來,所以l不是空懸參考,它是指向kconst左值參考,

auto與decltype

從C++11開始,auto關鍵字用于自動推導型別,用的是模板引數推導的規則:如果是拷貝串列初始化,則對應模板引數為std::initializer_list<T>,否則把auto替換為T,至于詳細的模板引數推導規則,要介紹的話未免喧賓奪主了,

還好,這不是我們的重點,在引出重點之前,我們還得先看decltype

decltype用于宣告一個型別("declare type"),有兩種語法:

  • decltype(entity)

  • decltype(expression)

第一種,decltype的引數是沒有括號包裹的識別符號或類成員,則decltype產生該物體的型別;如果是結構化系結,則產生被引型別,

第二種,decltype的引數是不能匹配第一種的任何運算式,其型別為T,則根據其運算式類別討論:

  • 如果是xvalue,產生T&&——#define is_xvalue(x) std::is_rvalue_reference<decltype((x))>::value

  • 如果是lvalue,產生T&——#define is_lvalue(x) std::is_lvalue_reference<decltype((x))>::value

  • 如果是prvalue,產生T——#define is_prvalue(x) !std::is_reference<decltype((x))>::value

因此,decltype(x)decltype((x))產生的型別通常是不同的,

對于不帶參考修飾的auto,初始化器的運算式類別會被抹去,為此C++14引入了新語法decltype(auto),產生的型別為decltype(expr),其中expr為初始化器,對于區域變數,等號右邊加上一對圓括號,可以保留運算式類別,

#include <utility>
#include <type_traits>

int non_reference() { return 1; }
int& lvalue_reference() { static int i; return i; }
const int& const_lvalue_reference() { return lvalue_reference(); }
int&& rvalue_reference() { static int i; return std::move(i); }

int main()
{
    auto [s1, s2] = std::pair(2, 3);
    auto&& t1 = s1;
    static_assert(!std::is_reference<decltype(s1)>::value);
    static_assert(std::is_lvalue_reference<decltype(t1)>::value);

    int i1 = 4;
    auto i2 = i1;
    decltype(auto) i3 = i1;
    decltype(auto) i4{i1};
    decltype(auto) i5 = (i1);
    static_assert(!std::is_reference<decltype(i2)>::value);
    static_assert(!std::is_reference<decltype(i3)>::value);
    static_assert(!std::is_reference<decltype(i4)>::value);
    static_assert(std::is_lvalue_reference<decltype(i5)>::value);

    auto n1 = non_reference();
    decltype(auto) n2 = non_reference();
    auto&& n3 = non_reference();
    static_assert(!std::is_reference<decltype(n1)>::value, "");
    static_assert(!std::is_reference<decltype(n2)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(n3)>::value, "");

    auto l1 = lvalue_reference();
    decltype(auto) l2 = lvalue_reference();
    auto&& l3 = lvalue_reference();
    static_assert(!std::is_reference<decltype(l1)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(l2)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(l3)>::value, "");

    auto c1 = const_lvalue_reference();
    decltype(auto) c2 = const_lvalue_reference();
    auto&& c3 = const_lvalue_reference();
    static_assert(!std::is_reference<decltype(c1)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(c2)>::value, "");
    static_assert(std::is_lvalue_reference<decltype(c3)>::value, "");

    auto r1 = rvalue_reference();
    decltype(auto) r2 = rvalue_reference();
    auto&& r3 = rvalue_reference();
    static_assert(!std::is_reference<decltype(r1)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(r2)>::value, "");
    static_assert(std::is_rvalue_reference<decltype(r3)>::value, "");
}

auto定義的變數都是int型別,無論函式的回傳型別的參考和const修飾;用decltype(auto)定義的變數的型別與函式回傳型別相同;auto&&是轉發參考,n3型別為int&&,其余與decltype(auto)相同,

C++17運算式類別

眾所周知,編譯器常會執行NRVO(named return value optimization),減少一次對函式回傳值的移動或拷貝,不過,這屬于C++標準說編譯器可以做的行為,卻沒有保證編譯器會這么做,因此客戶不能對此作出假設,從而需要提供一個拷貝或移動建構式,盡管它們可能不會被呼叫,然而,并不是所有情況下都能提供移動建構式,即使能移動建構式也未必只是一個指標的交換,總之,我們明知移動建構式不會被呼叫卻還要硬著頭皮提供一個,這樣做非常形式主義,

所以,C++17規定了拷貝省略,確保在以下情況下,即使拷貝或移動建構式有可觀察的效果,它們也不會被呼叫,原本要拷貝或移動的物件直接在目標位置構造:

  • return運算式中,運算元是忽略cv修飾符以后的回傳型別的prvalue;

  • 在初始化中,初始化器是與變數相同型別的prvalue,

值得一提的是,這類行為在C++17中不能算是一種優化,因為不存在用來拷貝或移動的臨時物件,事實上,C++17重新定義了運算式類別:

  • glvalue的求值能確定物件、位域、函式的身份;

  • prvalue的求值初始化物件或位域,或計算運算元的值,由背景關系決定;

  • xvalue是表示一個物件或位域的資源能被重用的glvalue;

  • lvalue是不是xvalue的glvalue;

  • rvalue是prvalue或xvalue,

這個定義在功能上與C++11中的相同,但是更清晰地指出了glvalue和prvalue的區別——glvalue產生地址,prvalue執行初始化,

prvalue初始化的物件由背景關系決定:在拷貝省略的情形下,prvalue不曾有關聯的物件;其他情形下,prvalue將產生一個臨時物件,這個程序稱為臨時物體化(temporary materialization),

臨時物體化把一個完全型別的prvalue轉換成xvalue,在以下情形中發生:

  • 把參考系結到prvalue上;

  • 類prvalue被獲取成員;

  • 陣列prvalue被轉換為指標或下標取元素;

  • prvalue出現在大括號初始化串列中,用于初始化一個std::initializer_list<T>

  • 被使用typeidsizeof運算子;

  • 在陳述句expr;中或被轉換成void,即該運算式的值被丟棄,

或者可以理解為,所有非拷貝省略的場合中的prvalue都會被臨時物體化,

class NonMoveable
{
public:
    int i = 1;
    NonMoveable(int i) : i(i) { }
    NonMoveable(NonMoveable&&) = delete;
};

NonMoveable make(int i)
{
    return NonMoveable{i};
}

void take(NonMoveable nm)
{
    return static_cast<void>(nm);
}

int main()
{
    auto nm = make(2);
    auto nm2 = NonMoveable{make(3)};
    // take(nm);
    take(make(4));
    take(NonMoveable{make(5)});
}

NonMoveable的移動建構式被宣告為delete,于是拷貝建構式也被隱式delete,在auto nm = make(2);中,NonMoveable{i}為prvalue,根據拷貝省略的第一條規則,它直接構造為回傳值;回傳值是NonMoveable的prvalue,與nm型別相同,根據第二條規則,這個prvalue直接在nm的位置上構造;兩部分結合,該宣告式相當于NonMoveable nm{2};

在MSVC中,這段代碼不能通過編譯,這是編譯器未能嚴格遵守C++標準的緣故,然而,如果在NonMoveable的移動建構式中添加輸出陳述句,程式運行起來也沒有任何輸出,即使在Debug模式下、即使用C++11標準編譯都如此,這也側面反映出拷貝省略的意義,

總結

C++11規定每個運算式都屬于lvalue、xvalue和prvalue三個類別之一,運算式另可分為lvalue和rvalue,或glvalue和prvalue,回傳右值參考的函式呼叫是xvalue,右值參考型別的變數是lvalue,

const左值參考和右值參考可以系結臨時物件,但是臨時物件的宣告周期只能延長一次,回傳一個指向區域變數的右值參考也會導致空懸參考,

識別符號加上一對圓括號成為運算式,decltype用于運算式可以根據其類別產生相應的型別,用decltype(auto)宣告變數可以保留運算式類別,

C++17中prvalue是否有關聯物件由背景關系決定,拷貝省略規定了特定情況下物件不經拷貝或移動直接構造,NRVO成為強制性標準,使不能被移動的物件在語意上可以值傳遞,

參考

  • Value categories - cppreference.com

  • Value categories - [l, gl, x, r, pr]values

  • Value Categories in C++17

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/24317.html

標籤:C++

上一篇:C++基礎之string物件

下一篇:OpenCV開發筆記(五十九):紅胖子8分鐘帶你深入了解分水嶺演算法(圖文并茂+淺顯易懂+程式原始碼)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more